Skip to content

Commit

Permalink
internal/ui: add a length check for uniform variables
Browse files Browse the repository at this point in the history
  • Loading branch information
hajimehoshi committed Jul 29, 2023
1 parent 5ddf1df commit d0e4023
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 0 deletions.
4 changes: 4 additions & 0 deletions image.go
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,8 @@ var _ [len(DrawTrianglesShaderOptions{}.Images) - graphics.ShaderImageCount]stru
//
// When a specified image is non-nil and is disposed, DrawTrianglesShader panics.
//
// If a specified uniform variable's length or type doesn't match with an expected one, DrawTrianglesShader panics.
//
// When the image i is disposed, DrawTrianglesShader does nothing.
func (i *Image) DrawTrianglesShader(vertices []Vertex, indices []uint16, shader *Shader, options *DrawTrianglesShaderOptions) {
i.copyCheck()
Expand Down Expand Up @@ -724,6 +726,8 @@ var _ [len(DrawRectShaderOptions{}.Images)]struct{} = [graphics.ShaderImageCount
//
// When one of the specified image is non-nil and is disposed, DrawRectShader panics.
//
// If a specified uniform variable's length or type doesn't match with an expected one, DrawRectShader panics.
//
// When the image i is disposed, DrawRectShader does nothing.
func (i *Image) DrawRectShader(width, height int, shader *Shader, options *DrawRectShaderOptions) {
i.copyCheck()
Expand Down
12 changes: 12 additions & 0 deletions internal/ui/shader.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,25 @@ func (s *Shader) AppendUniforms(dst []uint32, uniforms map[string]any) []uint32
t := v.Type()
switch t.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if typ.Uint32Count() != 1 {
panic(fmt.Sprintf("ui: unexpected uniform value for %s (%s)", name, typ.String()))
}
dst[idx] = uint32(v.Int())
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
if typ.Uint32Count() != 1 {
panic(fmt.Sprintf("ui: unexpected uniform value for %s (%s)", name, typ.String()))
}
dst[idx] = uint32(v.Uint())
case reflect.Float32, reflect.Float64:
if typ.Uint32Count() != 1 {
panic(fmt.Sprintf("ui: unexpected uniform value for %s (%s)", name, typ.String()))
}
dst[idx] = math.Float32bits(float32(v.Float()))
case reflect.Slice, reflect.Array:
l := v.Len()
if typ.Uint32Count() != l {
panic(fmt.Sprintf("ui: unexpected uniform value for %s (%s)", name, typ.String()))
}
switch t.Elem().Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
for i := 0; i < l; i++ {
Expand Down
106 changes: 106 additions & 0 deletions shader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1854,3 +1854,109 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
t.Errorf("got: %v, want: %v", got, want)
}
}

func TestShaderUniformSizes(t *testing.T) {
const w, h = 16, 16

dst := ebiten.NewImage(w, h)
s, err := ebiten.NewShader([]byte(`//kage:unit pixel
package main
var U vec4
var V [3]float
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
return vec4(0)
}
`))
if err != nil {
t.Fatal(err)
}

tests := []struct {
uniforms map[string]any
err bool
}{
{
uniforms: nil,
err: false,
},
{
uniforms: map[string]any{
"U": 1,
},
err: true,
},
{
uniforms: map[string]any{
"U": "1",
},
err: true,
},
{
uniforms: map[string]any{
"U": []int32{1, 2, 3},
},
err: true,
},
{
uniforms: map[string]any{
"U": []int32{1, 2, 3, 4},
},
err: false,
},
{
uniforms: map[string]any{
"U": []int32{1, 2, 3, 4, 5},
},
err: true,
},
{
uniforms: map[string]any{
"V": 1,
},
err: true,
},
{
uniforms: map[string]any{
"V": "1",
},
err: true,
},
{
uniforms: map[string]any{
"V": []int32{1, 2},
},
err: true,
},
{
uniforms: map[string]any{
"V": []int32{1, 2, 3},
},
err: false,
},
{
uniforms: map[string]any{
"V": []int32{1, 2, 3, 4},
},
err: true,
},
}
for _, tc := range tests {
tc := tc
t.Run(fmt.Sprintf("%v", tc.uniforms), func(t *testing.T) {
defer func() {
r := recover()
if r != nil && !tc.err {
t.Errorf("DrawRectShader must not panic but did")
} else if r == nil && tc.err {
t.Errorf("DrawRectShader must panic but does not")
}
}()
op := &ebiten.DrawRectShaderOptions{}
op.Uniforms = tc.uniforms
dst.DrawRectShader(w, h, s, op)
})
}
}

0 comments on commit d0e4023

Please sign in to comment.