mirror of
https://github.com/bloeys/nmage.git
synced 2025-12-29 05:18:21 +00:00
Update ubo.SetStruct to handle nested structs
This commit is contained in:
@ -120,11 +120,7 @@ func addUniformBufferFieldsToArray(startAlignedOffset uint16, arrayToAddTo *[]Un
|
||||
subfieldsAlignedOffset := uint16(addUniformBufferFieldsToArray(startAlignedOffset+alignedOffset, arrayToAddTo, f.Subfields))
|
||||
|
||||
// Pad structs to 16 byte boundary
|
||||
subfieldsAlignmentError := subfieldsAlignedOffset % 16
|
||||
if subfieldsAlignmentError != 0 {
|
||||
subfieldsAlignedOffset += 16 - subfieldsAlignmentError
|
||||
}
|
||||
|
||||
padTo16Boundary(&subfieldsAlignedOffset)
|
||||
alignedOffset += subfieldsAlignedOffset * f.Count
|
||||
|
||||
} else {
|
||||
@ -135,6 +131,13 @@ func addUniformBufferFieldsToArray(startAlignedOffset uint16, arrayToAddTo *[]Un
|
||||
return uint32(alignedOffset)
|
||||
}
|
||||
|
||||
func padTo16Boundary[T uint16 | int | int32](val *T) {
|
||||
alignmentError := *val % 16
|
||||
if alignmentError != 0 {
|
||||
*val += 16 - alignmentError
|
||||
}
|
||||
}
|
||||
|
||||
func (ub *UniformBuffer) getField(fieldId uint16, fieldType ElementType) UniformBufferField {
|
||||
|
||||
for i := 0; i < len(ub.Fields); i++ {
|
||||
@ -203,10 +206,10 @@ func (ub *UniformBuffer) SetMat4(fieldId uint16, val *gglm.Mat4) {
|
||||
}
|
||||
|
||||
func (ub *UniformBuffer) SetStruct(inputStruct any) {
|
||||
setStruct(ub.Fields, make([]byte, ub.Size), inputStruct, 1000_000, false)
|
||||
setStruct(ub.Fields, make([]byte, ub.Size), inputStruct, 1000_000, false, 0)
|
||||
}
|
||||
|
||||
func setStruct(fields []UniformBufferField, buf []byte, inputStruct any, maxFieldsToConsume int, onlyBufWrite bool) (bytesWritten, fieldsConsumed int) {
|
||||
func setStruct(fields []UniformBufferField, buf []byte, inputStruct any, maxFieldsToConsume int, onlyBufWrite bool, writeOffset int) (bytesWritten, fieldsConsumed int) {
|
||||
|
||||
if len(fields) == 0 {
|
||||
return
|
||||
@ -240,6 +243,7 @@ func setStruct(fields []UniformBufferField, buf []byte, inputStruct any, maxFiel
|
||||
isArray := kind == reflect.Slice || kind == reflect.Array
|
||||
if isArray {
|
||||
elementType = valField.Type().Elem()
|
||||
kind = elementType.Kind()
|
||||
} else {
|
||||
elementType = valField.Type()
|
||||
}
|
||||
@ -249,7 +253,7 @@ func setStruct(fields []UniformBufferField, buf []byte, inputStruct any, maxFiel
|
||||
}
|
||||
|
||||
typeMatches := false
|
||||
bytesWritten = int(ubField.AlignedOffset)
|
||||
bytesWritten = int(ubField.AlignedOffset) + writeOffset
|
||||
|
||||
switch ubField.Type {
|
||||
|
||||
@ -383,15 +387,42 @@ func setStruct(fields []UniformBufferField, buf []byte, inputStruct any, maxFiel
|
||||
}
|
||||
|
||||
case DataTypeStruct:
|
||||
|
||||
typeMatches = kind == reflect.Struct
|
||||
|
||||
if typeMatches {
|
||||
|
||||
setStructBytesWritten, setStructFieldsConsumed := setStruct(fields[fieldIndex+1:], buf, valField.Interface(), valField.NumField(), true)
|
||||
if isArray {
|
||||
|
||||
bytesWritten += setStructBytesWritten
|
||||
fieldIndex += setStructFieldsConsumed
|
||||
fieldsConsumed += setStructFieldsConsumed
|
||||
offset := 0
|
||||
arrSize := valField.Len()
|
||||
fieldsToUse := fields[fieldIndex+1:]
|
||||
for i := 0; i < arrSize; i++ {
|
||||
|
||||
setStructBytesWritten, setStructFieldsConsumed := setStruct(fieldsToUse, buf, valField.Index(i).Interface(), elementType.NumField(), true, offset*i)
|
||||
|
||||
if offset == 0 {
|
||||
offset = setStructBytesWritten
|
||||
padTo16Boundary(&offset)
|
||||
|
||||
bytesWritten += offset * arrSize
|
||||
|
||||
// Tracking consumed fields is needed because if we have a struct inside another struct
|
||||
// elementType.NumField() will only give us the fields consumed by the first struct,
|
||||
// but we need to count all fields of all nested structs inside this one
|
||||
fieldIndex += setStructFieldsConsumed
|
||||
fieldsConsumed += setStructFieldsConsumed
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
setStructBytesWritten, setStructFieldsConsumed := setStruct(fields[fieldIndex+1:], buf, valField.Interface(), valField.NumField(), true, writeOffset)
|
||||
|
||||
bytesWritten += setStructBytesWritten
|
||||
fieldIndex += setStructFieldsConsumed
|
||||
fieldsConsumed += setStructFieldsConsumed
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
@ -411,7 +442,7 @@ func setStruct(fields []UniformBufferField, buf []byte, inputStruct any, maxFiel
|
||||
gl.BufferSubData(gl.UNIFORM_BUFFER, 0, bytesWritten, gl.Ptr(&buf[0]))
|
||||
}
|
||||
|
||||
return bytesWritten - int(fields[0].AlignedOffset), fieldsConsumed
|
||||
return bytesWritten - int(fields[0].AlignedOffset) - writeOffset, fieldsConsumed
|
||||
}
|
||||
|
||||
func Write32BitIntegerToByteBuf[T uint32 | int32](buf []byte, startIndex *int, val T) {
|
||||
|
||||
36
main.go
36
main.go
@ -677,7 +677,7 @@ func (g *Game) Init() {
|
||||
|
||||
// Ubos
|
||||
g.initUbos()
|
||||
// testUbos()
|
||||
testUbos()
|
||||
|
||||
// Initial camera update
|
||||
cam.Update()
|
||||
@ -873,7 +873,8 @@ func testUbos() {
|
||||
XX int32
|
||||
Z2 TestUBO3_0
|
||||
XX2 int32
|
||||
Abcd TestUBO3_X
|
||||
Abcd [2]TestUBO3_X
|
||||
XX3 int32
|
||||
}
|
||||
|
||||
ubo3 := buffers.NewUniformBuffer([]buffers.UniformBufferFieldInput{
|
||||
@ -890,13 +891,14 @@ func testUbos() {
|
||||
{Id: 8, Type: buffers.DataTypeInt32}, // 04 80
|
||||
}},
|
||||
{Id: 9, Type: buffers.DataTypeInt32}, // 04 96
|
||||
{Id: 10, Type: buffers.DataTypeStruct, Subfields: []buffers.UniformBufferFieldInput{ // 00 112
|
||||
{Id: 10, Type: buffers.DataTypeStruct, Count: 2, Subfields: []buffers.UniformBufferFieldInput{ // 00 112
|
||||
{Id: 11, Type: buffers.DataTypeStruct, Subfields: []buffers.UniformBufferFieldInput{ // 00 112
|
||||
{Id: 12, Type: buffers.DataTypeStruct, Subfields: []buffers.UniformBufferFieldInput{ // 00 112
|
||||
{Id: 13, Type: buffers.DataTypeInt32}, // 04 112
|
||||
}},
|
||||
}},
|
||||
}},
|
||||
{Id: 14, Type: buffers.DataTypeInt32},
|
||||
}) // 116
|
||||
ubo3.Bind()
|
||||
|
||||
@ -919,13 +921,23 @@ func testUbos() {
|
||||
X: 8,
|
||||
},
|
||||
XX2: 321,
|
||||
Abcd: TestUBO3_X{
|
||||
V: TestUBO3_Y{
|
||||
V: TestUBO3_Z{
|
||||
V: 9911,
|
||||
Abcd: [2]TestUBO3_X{
|
||||
{
|
||||
V: TestUBO3_Y{
|
||||
V: TestUBO3_Z{
|
||||
V: 9911,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
V: TestUBO3_Y{
|
||||
V: TestUBO3_Z{
|
||||
V: 9922,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
XX3: 818,
|
||||
}
|
||||
|
||||
ubo3.SetStruct(s3)
|
||||
@ -937,7 +949,9 @@ func testUbos() {
|
||||
ubo3Xx := 0
|
||||
ubo3SZ2X := 0
|
||||
ubo3Xx2 := 0
|
||||
ubo3AbcdV := 0
|
||||
ubo3AbcdV1 := 0
|
||||
ubo3AbcdV2 := 0
|
||||
ubo3Xx3 := 0
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 0, 4, gl.Ptr(&ubo3F32))
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 16, 4, gl.Ptr(&ubo3SF32))
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 32, 16, gl.Ptr(&ubo3SV3.Data[0]))
|
||||
@ -946,9 +960,11 @@ func testUbos() {
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 64, 4, gl.Ptr(&ubo3Xx))
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 80, 4, gl.Ptr(&ubo3SZ2X))
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 96, 4, gl.Ptr(&ubo3Xx2))
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 112, 4, gl.Ptr(&ubo3AbcdV))
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 112, 4, gl.Ptr(&ubo3AbcdV1))
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 128, 4, gl.Ptr(&ubo3AbcdV2))
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 144, 4, gl.Ptr(&ubo3Xx3))
|
||||
|
||||
fmt.Printf("ubo3_f32=%f\nubo3_s_f32=%f\nubo3_s_v3=%s\nubo3_s_zero_x=%d\nubo3_xx=%d\nubo3_z2_x=%d\nubo3_xx2=%d\nubo3_abcd_v=%d\n", ubo3F32, ubo3SF32, ubo3SV3.String(), ubo3SZeroX, ubo3Xx, ubo3SZ2X, ubo3Xx2, ubo3AbcdV)
|
||||
fmt.Printf("ubo3_f32=%f\nubo3_s_f32=%f\nubo3_s_v3=%s\nubo3_s_zero_x=%d\nubo3_xx=%d\nubo3_z2_x=%d\nubo3_xx2=%d\nubo3_abcd_v1=%d\nubo3_abcd_v2=%d\nubo3_xx3=%d\n", ubo3F32, ubo3SF32, ubo3SV3.String(), ubo3SZeroX, ubo3Xx, ubo3SZ2X, ubo3Xx2, ubo3AbcdV1, ubo3AbcdV2, ubo3Xx3)
|
||||
}
|
||||
|
||||
func (g *Game) initFbos() {
|
||||
|
||||
Reference in New Issue
Block a user