Skip to content

Added Packed_*_Array support #10

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

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions addons/compute_worker/gpu_uniforms/gpu_packed_int32_array.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# GLSL data type encoding: `int`

extends GPUUniform
class_name GPU_PackedInt32Array

enum UNIFORM_TYPES{
UNIFORM_BUFFER,
STORAGE_BUFFER
}

## The initial data supplied to the uniform
@export var data: PackedInt32Array = PackedInt32Array()
## The size of the array as defined in the shader. Only used if `data` is not defined.
@export var array_size: int = 0
## The shader binding for this uniform
@export var binding: int = 0
## Type of uniform to create. `UNIFORM_BUFFER`s cannot be altered from within the shader
@export var uniform_type: UNIFORM_TYPES = UNIFORM_TYPES.UNIFORM_BUFFER

var data_rid: RID = RID()
var uniform: RDUniform = RDUniform.new()


func initialize(rd: RenderingDevice) -> RDUniform:

if data.is_empty():
if array_size > 0:
data.resize(array_size)
else:
printerr("You must define the uniform's `data` or `array_size`.")
return

# Create the buffer using our initial data
data_rid = create_rid(rd)

# Create RDUniform object using the provided binding id and data
return create_uniform()


func create_uniform() -> RDUniform:

match uniform_type:
UNIFORM_TYPES.UNIFORM_BUFFER:
uniform.uniform_type = RenderingDevice.UNIFORM_TYPE_UNIFORM_BUFFER
UNIFORM_TYPES.STORAGE_BUFFER:
uniform.uniform_type = RenderingDevice.UNIFORM_TYPE_STORAGE_BUFFER

uniform.binding = binding
uniform.add_id(data_rid)

return uniform


func create_rid(rd: RenderingDevice) -> RID:

var bytes = data.to_byte_array()

var buffer: RID = RID()

match uniform_type:
UNIFORM_TYPES.UNIFORM_BUFFER:
bytes = pad_byte_array_std140(bytes)
buffer = rd.uniform_buffer_create(bytes.size(), bytes)
UNIFORM_TYPES.STORAGE_BUFFER:
buffer = rd.storage_buffer_create(bytes.size(), bytes)

return buffer


func get_uniform_data(rd: RenderingDevice) -> PackedInt32Array:
var out := rd.buffer_get_data(data_rid)
return out.to_int32_array()


func set_uniform_data(rd: RenderingDevice, array: PackedInt32Array) -> void:
var sb_data = array.to_byte_array()
rd.buffer_update(data_rid, 0 , sb_data.size(), sb_data)


func pad_byte_array_std140(arr: PackedByteArray) -> PackedByteArray:

arr.resize(arr.size() * 2)
var next_offset = 0

for i in range(arr.size()):
if next_offset + 4 > arr.size():
break
arr.encode_double(next_offset + 4, 0.0)
next_offset += 16

return arr
10 changes: 10 additions & 0 deletions addons/compute_worker/gpu_uniforms/gpu_packed_int32_array.tres
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[gd_resource type="Resource" script_class="GPU_packed_int32_array" load_steps=2 format=3 uid="uid://b5uu7tqhsjaam"]

[ext_resource type="Script" path="res://addons/compute_worker/gpu_uniforms/gpu_packed_int32_array.gd" id="1_571yc"]

[resource]
script = ExtResource("1_571yc")
data = null
binding = 0
uniform_type = 0
alias = ""
79 changes: 79 additions & 0 deletions addons/compute_worker/gpu_uniforms/gpu_packed_vector2_array.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# GLSL data type encoding: `vec4[]`, `vec3[]`

extends GPUUniform
class_name GPU_PackedVector2Array

enum UNIFORM_TYPES{
UNIFORM_BUFFER,
STORAGE_BUFFER
}

## The initial data supplied to the uniform
@export var data: PackedVector2Array = PackedVector2Array()
## The size of the array as defined in the shader. Only used if `data` is not defined.
@export var array_size: int = 0
## The shader binding for this uniform
@export var binding: int = 0
## Type of uniform to create. `UNIFORM_BUFFER`s cannot be altered from within the shader
@export var uniform_type: UNIFORM_TYPES = UNIFORM_TYPES.UNIFORM_BUFFER

var data_rid: RID = RID()
var uniform: RDUniform = RDUniform.new()


func initialize(rd: RenderingDevice) -> RDUniform:

if data.is_empty():

assert(array_size > 0, "You must define the uniform's `data` or `array_size`.")

if array_size > 0:
data.resize(array_size)

# Create the buffer using our initial data
data_rid = create_rid(rd)

# Create RDUniform object using the provided binding id and data
return create_uniform()


func create_uniform() -> RDUniform:

match uniform_type:
UNIFORM_TYPES.UNIFORM_BUFFER:
uniform.uniform_type = RenderingDevice.UNIFORM_TYPE_UNIFORM_BUFFER
UNIFORM_TYPES.STORAGE_BUFFER:
uniform.uniform_type = RenderingDevice.UNIFORM_TYPE_STORAGE_BUFFER

uniform.binding = binding
uniform.add_id(data_rid)

return uniform


func create_rid(rd: RenderingDevice) -> RID:

var bytes = vec2_array_to_byte_array(data)

var buffer: RID = RID()

match uniform_type:
UNIFORM_TYPES.UNIFORM_BUFFER:
buffer = rd.uniform_buffer_create(bytes.size(), bytes)
UNIFORM_TYPES.STORAGE_BUFFER:
buffer = rd.storage_buffer_create(bytes.size(), bytes)

return buffer


func get_uniform_data(rd: RenderingDevice) -> PackedVector2Array:
var out := rd.buffer_get_data(data_rid)
return byte_array_to_vec2_array(out)


func set_uniform_data(rd: RenderingDevice, array: PackedVector2Array) -> void:
var sb_data = vec2_array_to_byte_array(array)
rd.buffer_update(data_rid, 0 , sb_data.size(), sb_data)



11 changes: 11 additions & 0 deletions addons/compute_worker/gpu_uniforms/gpu_packed_vector2_array.tres
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[gd_resource type="Resource" script_class="GPU_PackedVector2Array" load_steps=2 format=3 uid="uid://c1pyh5mnrbuwm"]

[ext_resource type="Script" path="res://addons/compute_worker/gpu_uniforms/gpu_packed_vector2_array.gd" id="1_cmbw3"]

[resource]
script = ExtResource("1_cmbw3")
data = null
array_size = 0
binding = 0
uniform_type = 0
alias = ""
37 changes: 32 additions & 5 deletions addons/compute_worker/gpu_uniforms/gpu_struct.gd
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ func create_rid(rd: RenderingDevice) -> RID:

func get_uniform_data(rd: RenderingDevice):
var out := rd.buffer_get_data(data_rid)

return decode_struct(out)


Expand All @@ -71,13 +72,21 @@ func set_uniform_data(rd: RenderingDevice, data: Array) -> void:
## Encode the contents of the passed in `data` Array to PackedByteArray.
## Contents of `data` must match the order and data types defined in `struct_data`.
func encode_struct(data: Array, init: bool = false) -> PackedByteArray:

var arr: PackedByteArray = PackedByteArray()
var data_index = 0
print("encode_struct data: ", data)

for type_obj in struct_data:

match typeof(type_obj):
TYPE_PACKED_VECTOR3_ARRAY:
arr.append_array(vec3_array_to_byte_array(data[data_index]))
TYPE_PACKED_VECTOR2_ARRAY:
arr.append_array(vec2_array_to_byte_array(data[data_index]))
TYPE_VECTOR2I:
arr.append_array(vec2i_to_byte_array(data[data_index]))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TYPE_VECTOR2I and TYPE_VECTOR2 require different alignments when inside a struct. Like with arrays, alignments for struct members are rounded up to the alignment of a vec4. So for these two types, we'll need separate functions to get the byte arrays with the extra padding (+2 components).

TYPE_VECTOR2:
arr.append_array(vec2_to_byte_array(data[data_index]))
TYPE_VECTOR3I:
arr.append_array(vec3i_to_byte_array(data[data_index]))
TYPE_COLOR:
Expand All @@ -94,7 +103,7 @@ func encode_struct(data: Array, init: bool = false) -> PackedByteArray:
if !init:
if pad_byte_array(arr).size() != byte_length && uniform.uniform_type == RenderingDevice.UNIFORM_TYPE_UNIFORM_BUFFER:
printerr("Data for uniform: " + str(alias) + " does not match struct requirements. Needs: " + str(byte_length) + " was given: " + str(arr.size()))

print("encode_struct pad: ", pad_byte_array(arr).to_float32_array())
return pad_byte_array(arr)


Expand All @@ -110,14 +119,19 @@ func pad_byte_array(arr: PackedByteArray):
## Decode the contents of the passed in PackedByteArray to an Array matching
## the order and data types defined in `struct_data`.
func decode_struct(data: PackedByteArray) -> Array:

print("decode_struct data: ", data.to_float32_array())
var arr: Array = []

var offset: int = 0

for i in range(struct_data.size()):

match typeof(struct_data[i]):

TYPE_PACKED_VECTOR3_ARRAY:
var arr_size = struct_data[i].size()
var pvec3arr = byte_array_to_vec3_array(data.slice(offset, offset + 16*arr_size))
arr.push_back(pvec3arr)
offset += 16*arr_size
TYPE_VECTOR3I:
var vec = byte_array_to_vec3(data.slice(offset, offset + 32))
arr.push_back(vec)
Expand All @@ -130,6 +144,19 @@ func decode_struct(data: PackedByteArray) -> Array:
var vec = byte_array_to_vec3(data.slice(offset, offset + 32))
arr.push_back(vec)
offset += 32
TYPE_PACKED_VECTOR2_ARRAY:
var arr_size = struct_data[i].size()
var pvec2arr = byte_array_to_vec2_array(data.slice(offset, offset + 16*arr_size))
arr.push_back(pvec2arr)
offset += 16*arr_size
TYPE_VECTOR2I:
var vec = byte_array_to_vec2(data.slice(offset, offset + 16))
arr.push_back(vec)
offset += 16
TYPE_VECTOR2:
var vec = byte_array_to_vec2(data.slice(offset, offset + 16))
arr.push_back(vec)
offset += 16
TYPE_FLOAT:
var flo = byte_array_to_float(data.slice(offset, offset + 8))
arr.push_back(flo)
Expand All @@ -138,5 +165,5 @@ func decode_struct(data: PackedByteArray) -> Array:
var integer = byte_array_to_int(data.slice(offset, offset + 4))
arr.push_back(integer)
offset += 4
print("decode_struct arr: ", arr)
return arr
3 changes: 1 addition & 2 deletions addons/compute_worker/gpu_uniforms/gpu_struct_array.gd
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,9 @@ func create_rid(rd: RenderingDevice) -> RID:
return buffer


func get_uniform_data(rd: RenderingDevice) -> Array[Array]:
func get_uniform_data(rd: RenderingDevice):

var out := rd.buffer_get_data(data_rid)

var arr: Array = []

@warning_ignore("integer_division")
Expand Down
61 changes: 57 additions & 4 deletions addons/compute_worker/gpu_uniforms/gpu_uniform.gd
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func byte_array_to_uint(array: PackedByteArray) -> int:
return array.decode_u32(0)


## Convert GLSL `dvec2` to Vector2
## Convert GLSL `vec2` to Vector2
func byte_array_to_vec2(array: PackedByteArray) -> Vector2:

var dup = array.duplicate()
Expand Down Expand Up @@ -139,10 +139,15 @@ func byte_array_to_vec3(array: PackedByteArray) -> Vector3:


## Convert a Vector3 to GLSL equivalent `dvec3, dvec4` format
func vec3_to_byte_array(vector: Vector3) -> PackedByteArray:
func dvec3_to_byte_array(vector: Vector3) -> PackedByteArray:

return PackedFloat64Array([vector.x, vector.y, vector.z, 0.0]).to_byte_array()

## Convert a Vector3 to GLSL equivalent `vec3, vec4` format
func vec3_to_byte_array(vector: Vector3) -> PackedByteArray:

return PackedFloat32Array([vector.x, vector.y, vector.z, 0.0]).to_byte_array()


## Convert a Vector3i to GLSL equivalent `ivec3, ivec4` format
func vec3i_to_byte_array(vector: Vector3i) -> PackedByteArray:
Expand All @@ -151,6 +156,46 @@ func vec3i_to_byte_array(vector: Vector3i) -> PackedByteArray:
# because the alignment spec for GLSL vec3s requires 16bytes
return PackedInt32Array([vector.x, vector.y, vector.z, 0]).to_byte_array()

func vec2i_to_byte_array(vector: Vector2i) -> PackedByteArray:

# We have to add a value for the "w" field for the vector,
# because the alignment spec for GLSL vec2s requires 12bytes
return PackedInt32Array([vector.x, vector.y, 0]).to_byte_array()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The component in the Z position here is not necessary. vec2s in GLSL only need the x and y elements. As opposed to vec3s, which are treated as 4-component vectors by GLSL.



## Convert an array of Vector3s to GLSL equivalent `vec2[]` format
func vec2_array_to_byte_array(array: PackedVector2Array):

var bytes: PackedByteArray = PackedByteArray()

for vector in array:
var vec: Vector3 = Vector3()

vec.x = vector.x
vec.y = vector.y



var float_arr = PackedFloat32Array([vec.x, vec.y]).to_byte_array()
bytes.append_array(float_arr)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vectors that are inside arrays in GLSL have their alignment rounded up to a multiple of 4 of the base alignment of its elements. So here, where we define float_arr, we would add two more components to the array to fill out the rest of the array element's space inside the array.


return bytes

## Convert GLSL `vec2[]` to an Array of Vector2s
func byte_array_to_vec2_array(bytes: PackedByteArray) -> PackedVector2Array:

var arr: PackedVector2Array = PackedVector2Array()

for v in range((16 + bytes.size()) / 16.0):

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the alignment of the elements in the array are rounded up to the alignment of a vec4, we can treat this array the same as we treat it in byte_array_to_vec3_array(), with an array stride of 16 bytes. It would essentially look just like byte_array_to_vec3_array(), we just build an array of Vector2s instead.

var vec = Vector2()

vec.x = bytes.decode_float(0 + (v * 8.0))
vec.y = bytes.decode_float(4 + (v * 8.0))
arr.append(vec)

return arr


## Convert an array of Vector3s to GLSL equivalent `vec3[], vec4[]` format
func vec3_array_to_byte_array(array: PackedVector3Array):
Expand All @@ -167,7 +212,7 @@ func vec3_array_to_byte_array(array: PackedVector3Array):

# We have to add a value for the "w" field for the vector,
# because the alignment spec for GLSL vec3s requires 16bytes
var float_arr = PackedFloat32Array([vector.x, vector.y, vector.z, 0.0]).to_byte_array()
var float_arr = PackedFloat32Array([vec.x, vec.y, vec.z, vec.w]).to_byte_array()
bytes.append_array(float_arr)

return bytes
Expand Down Expand Up @@ -195,9 +240,17 @@ func byte_array_to_vec3_array(bytes: PackedByteArray) -> PackedVector3Array:
func float_array_to_byte_array_64(array: Array[float]) -> PackedByteArray:
var bytes = PackedFloat64Array(array).to_byte_array()
return bytes


## Convert an array of Floats to GLSL equivalent `double[]`
func int_array_to_byte_array_32(array: Array[int]) -> PackedByteArray:
var bytes = PackedInt32Array(array).to_byte_array()
return bytes

## Convert a GLSL `double[]` to an Array of Floats
func byte_array_64_to_float_array(array: PackedByteArray) -> Array[float]:
return Array(array.to_float64_array())

## Convert a GLSL `int[]` to an Array of Ints
func byte_array_32_to_int_array(array: PackedByteArray) -> Array[float]:
return Array(array.to_int32_array())