internal/shader: introduce integer vectors (ivec2, ivec3, ivec4)

Closes #1911
This commit is contained in:
Hajime Hoshi 2022-11-20 15:36:07 +09:00
parent f09c4a624e
commit 0b9cbaa1ed
22 changed files with 795 additions and 53 deletions

View File

@ -1739,19 +1739,19 @@ func (s *Shader) flattenUniforms(uniforms [][]uint32) []uint32 {
} else {
fs = append(fs, 0)
}
case shaderir.Vec2:
case shaderir.Vec2, shaderir.IVec2:
if u != nil {
fs = append(fs, u...)
} else {
fs = append(fs, 0, 0)
}
case shaderir.Vec3:
case shaderir.Vec3, shaderir.IVec3:
if u != nil {
fs = append(fs, u...)
} else {
fs = append(fs, 0, 0, 0)
}
case shaderir.Vec4:
case shaderir.Vec4, shaderir.IVec4:
if u != nil {
fs = append(fs, u...)
} else {
@ -1824,7 +1824,7 @@ func (s *Shader) flattenUniforms(uniforms [][]uint32) []uint32 {
} else {
fs = append(fs, make([]uint32, (t.Length-1)*4+1)...)
}
case shaderir.Vec2:
case shaderir.Vec2, shaderir.IVec2:
if u != nil {
for j := 0; j < t.Length; j++ {
fs = append(fs, u[2*j:2*(j+1)]...)
@ -1835,7 +1835,7 @@ func (s *Shader) flattenUniforms(uniforms [][]uint32) []uint32 {
} else {
fs = append(fs, make([]uint32, (t.Length-1)*4+2)...)
}
case shaderir.Vec3:
case shaderir.Vec3, shaderir.IVec3:
if u != nil {
for j := 0; j < t.Length; j++ {
fs = append(fs, u[3*j:3*(j+1)]...)
@ -1846,7 +1846,7 @@ func (s *Shader) flattenUniforms(uniforms [][]uint32) []uint32 {
} else {
fs = append(fs, make([]uint32, (t.Length-1)*4+3)...)
}
case shaderir.Vec4:
case shaderir.Vec4, shaderir.IVec4:
if u != nil {
fs = append(fs, u...)
} else {

View File

@ -576,7 +576,7 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.
t := g.shaders[shaderID].ir.Uniforms[i]
switch t.Main {
case shaderir.Vec3:
case shaderir.Vec3, shaderir.IVec3:
// float3 requires 16-byte alignment (#2463).
v1 := make([]uint32, 4)
copy(v1[0:3], v[0:3])
@ -590,7 +590,7 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.
uniformVars[i] = v1
case shaderir.Array:
switch t.Sub[0].Main {
case shaderir.Vec3:
case shaderir.Vec3, shaderir.IVec3:
v1 := make([]uint32, t.Length*4)
for j := 0; j < t.Length; j++ {
offset0 := j * 3

View File

@ -470,6 +470,12 @@ func (c *context) uniforms(p program, location string, v []uint32, typ shaderir.
c.ctx.Uniform3fv(int32(l), uint32sToFloat32s(v))
case shaderir.Vec4:
c.ctx.Uniform4fv(int32(l), uint32sToFloat32s(v))
case shaderir.IVec2:
c.ctx.Uniform2iv(int32(l), uint32sToInt32s(v))
case shaderir.IVec3:
c.ctx.Uniform3iv(int32(l), uint32sToInt32s(v))
case shaderir.IVec4:
c.ctx.Uniform4iv(int32(l), uint32sToInt32s(v))
case shaderir.Mat2:
c.ctx.UniformMatrix2fv(int32(l), uint32sToFloat32s(v))
case shaderir.Mat3:

View File

@ -99,8 +99,11 @@ package gl
// typedef void (APIENTRYP GPUNIFORM1I)(GLint location, GLint v0);
// typedef void (APIENTRYP GPUNIFORM1IV)(GLint location, GLsizei count, const GLint * value);
// typedef void (APIENTRYP GPUNIFORM2FV)(GLint location, GLsizei count, const GLfloat * value);
// typedef void (APIENTRYP GPUNIFORM2IV)(GLint location, GLsizei count, const GLint * value);
// typedef void (APIENTRYP GPUNIFORM3FV)(GLint location, GLsizei count, const GLfloat * value);
// typedef void (APIENTRYP GPUNIFORM3IV)(GLint location, GLsizei count, const GLint * value);
// typedef void (APIENTRYP GPUNIFORM4FV)(GLint location, GLsizei count, const GLfloat * value);
// typedef void (APIENTRYP GPUNIFORM4IV)(GLint location, GLsizei count, const GLint * value);
// typedef void (APIENTRYP GPUNIFORMMATRIX2FV)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
// typedef void (APIENTRYP GPUNIFORMMATRIX3FV)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
// typedef void (APIENTRYP GPUNIFORMMATRIX4FV)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
@ -291,12 +294,21 @@ package gl
// static void glowUniform2fv(GPUNIFORM2FV fnptr, GLint location, GLsizei count, const GLfloat * value) {
// (*fnptr)(location, count, value);
// }
// static void glowUniform2iv(GPUNIFORM2IV fnptr, GLint location, GLsizei count, const GLint * value) {
// (*fnptr)(location, count, value);
// }
// static void glowUniform3fv(GPUNIFORM3FV fnptr, GLint location, GLsizei count, const GLfloat * value) {
// (*fnptr)(location, count, value);
// }
// static void glowUniform3iv(GPUNIFORM3IV fnptr, GLint location, GLsizei count, const GLint * value) {
// (*fnptr)(location, count, value);
// }
// static void glowUniform4fv(GPUNIFORM4FV fnptr, GLint location, GLsizei count, const GLfloat * value) {
// (*fnptr)(location, count, value);
// }
// static void glowUniform4iv(GPUNIFORM4IV fnptr, GLint location, GLsizei count, const GLint * value) {
// (*fnptr)(location, count, value);
// }
// static void glowUniformMatrix2fv(GPUNIFORMMATRIX2FV fnptr, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value) {
// (*fnptr)(location, count, transpose, value);
// }
@ -385,8 +397,11 @@ type defaultContext struct {
gpUniform1i C.GPUNIFORM1I
gpUniform1iv C.GPUNIFORM1IV
gpUniform2fv C.GPUNIFORM2FV
gpUniform2iv C.GPUNIFORM2IV
gpUniform3fv C.GPUNIFORM3FV
gpUniform3iv C.GPUNIFORM3IV
gpUniform4fv C.GPUNIFORM4FV
gpUniform4iv C.GPUNIFORM4IV
gpUniformMatrix2fv C.GPUNIFORMMATRIX2FV
gpUniformMatrix3fv C.GPUNIFORMMATRIX3FV
gpUniformMatrix4fv C.GPUNIFORMMATRIX4FV
@ -705,16 +720,31 @@ func (c *defaultContext) Uniform2fv(location int32, value []float32) {
runtime.KeepAlive(value)
}
func (c *defaultContext) Uniform2iv(location int32, value []int32) {
C.glowUniform2iv(c.gpUniform2iv, (C.GLint)(location), (C.GLsizei)(len(value)/2), (*C.GLint)(unsafe.Pointer(&value[0])))
runtime.KeepAlive(value)
}
func (c *defaultContext) Uniform3fv(location int32, value []float32) {
C.glowUniform3fv(c.gpUniform3fv, (C.GLint)(location), (C.GLsizei)(len(value)/3), (*C.GLfloat)(unsafe.Pointer(&value[0])))
runtime.KeepAlive(value)
}
func (c *defaultContext) Uniform3iv(location int32, value []int32) {
C.glowUniform3iv(c.gpUniform3iv, (C.GLint)(location), (C.GLsizei)(len(value)/3), (*C.GLint)(unsafe.Pointer(&value[0])))
runtime.KeepAlive(value)
}
func (c *defaultContext) Uniform4fv(location int32, value []float32) {
C.glowUniform4fv(c.gpUniform4fv, (C.GLint)(location), (C.GLsizei)(len(value)/4), (*C.GLfloat)(unsafe.Pointer(&value[0])))
runtime.KeepAlive(value)
}
func (c *defaultContext) Uniform4iv(location int32, value []int32) {
C.glowUniform4iv(c.gpUniform4iv, (C.GLint)(location), (C.GLsizei)(len(value)/4), (*C.GLint)(unsafe.Pointer(&value[0])))
runtime.KeepAlive(value)
}
func (c *defaultContext) UniformMatrix2fv(location int32, value []float32) {
C.glowUniformMatrix2fv(c.gpUniformMatrix2fv, (C.GLint)(location), (C.GLsizei)(len(value)/4), 0, (*C.GLfloat)(unsafe.Pointer(&value[0])))
runtime.KeepAlive(value)
@ -951,14 +981,26 @@ func (c *defaultContext) LoadFunctions() error {
if c.gpUniform2fv == nil {
return errors.New("gl: glUniform2fv is missing")
}
c.gpUniform2iv = (C.GPUNIFORM2IV)(c.getProcAddress("glUniform2iv"))
if c.gpUniform2iv == nil {
return errors.New("gl: glUniform2iv is missing")
}
c.gpUniform3fv = (C.GPUNIFORM3FV)(c.getProcAddress("glUniform3fv"))
if c.gpUniform3fv == nil {
return errors.New("gl: glUniform3fv is missing")
}
c.gpUniform3iv = (C.GPUNIFORM3IV)(c.getProcAddress("glUniform3iv"))
if c.gpUniform3iv == nil {
return errors.New("gl: glUniform3iv is missing")
}
c.gpUniform4fv = (C.GPUNIFORM4FV)(c.getProcAddress("glUniform4fv"))
if c.gpUniform4fv == nil {
return errors.New("gl: glUniform4fv is missing")
}
c.gpUniform4iv = (C.GPUNIFORM4IV)(c.getProcAddress("glUniform4iv"))
if c.gpUniform4iv == nil {
return errors.New("gl: glUniform4iv is missing")
}
c.gpUniformMatrix2fv = (C.GPUNIFORMMATRIX2FV)(c.getProcAddress("glUniformMatrix2fv"))
if c.gpUniformMatrix2fv == nil {
return errors.New("gl: glUniformMatrix2fv is missing")

View File

@ -84,8 +84,11 @@ type defaultContext struct {
fnUniform1i js.Value
fnUniform1iv js.Value
fnUniform2fv js.Value
fnUniform2iv js.Value
fnUniform3fv js.Value
fnUniform3iv js.Value
fnUniform4fv js.Value
fnUniform4iv js.Value
fnUniformMatrix2fv js.Value
fnUniformMatrix3fv js.Value
fnUniformMatrix4fv js.Value
@ -210,8 +213,11 @@ func NewDefaultContext(v js.Value) (Context, error) {
fnUniform1i: v.Get("uniform1i").Call("bind", v),
fnUniform1iv: v.Get("uniform1iv").Call("bind", v),
fnUniform2fv: v.Get("uniform2fv").Call("bind", v),
fnUniform2iv: v.Get("uniform2iv").Call("bind", v),
fnUniform3fv: v.Get("uniform3fv").Call("bind", v),
fnUniform3iv: v.Get("uniform3iv").Call("bind", v),
fnUniform4fv: v.Get("uniform4fv").Call("bind", v),
fnUniform4iv: v.Get("uniform4iv").Call("bind", v),
fnUniformMatrix2fv: v.Get("uniformMatrix2fv").Call("bind", v),
fnUniformMatrix3fv: v.Get("uniformMatrix3fv").Call("bind", v),
fnUniformMatrix4fv: v.Get("uniformMatrix4fv").Call("bind", v),
@ -582,6 +588,16 @@ func (c *defaultContext) Uniform2fv(location int32, value []float32) {
}
}
func (c *defaultContext) Uniform2iv(location int32, value []int32) {
l := c.getUniformLocation(location)
arr := jsutil.TemporaryInt32Array(len(value), value)
if c.webGL2 {
c.fnUniform2iv.Invoke(l, arr, 0, len(value))
} else {
c.fnUniform2iv.Invoke(l, arr.Call("subarray", 0, len(value)))
}
}
func (c *defaultContext) Uniform3fv(location int32, value []float32) {
l := c.getUniformLocation(location)
arr := jsutil.TemporaryFloat32Array(len(value), value)
@ -592,6 +608,16 @@ func (c *defaultContext) Uniform3fv(location int32, value []float32) {
}
}
func (c *defaultContext) Uniform3iv(location int32, value []int32) {
l := c.getUniformLocation(location)
arr := jsutil.TemporaryInt32Array(len(value), value)
if c.webGL2 {
c.fnUniform3iv.Invoke(l, arr, 0, len(value))
} else {
c.fnUniform3iv.Invoke(l, arr.Call("subarray", 0, len(value)))
}
}
func (c *defaultContext) Uniform4fv(location int32, value []float32) {
l := c.getUniformLocation(location)
arr := jsutil.TemporaryFloat32Array(len(value), value)
@ -602,6 +628,16 @@ func (c *defaultContext) Uniform4fv(location int32, value []float32) {
}
}
func (c *defaultContext) Uniform4iv(location int32, value []int32) {
l := c.getUniformLocation(location)
arr := jsutil.TemporaryInt32Array(len(value), value)
if c.webGL2 {
c.fnUniform4iv.Invoke(l, arr, 0, len(value))
} else {
c.fnUniform4iv.Invoke(l, arr.Call("subarray", 0, len(value)))
}
}
func (c *defaultContext) UniformMatrix2fv(location int32, value []float32) {
l := c.getUniformLocation(location)
arr := jsutil.TemporaryFloat32Array(len(value), value)

View File

@ -86,8 +86,11 @@ type defaultContext struct {
gpUniform1i uintptr
gpUniform1iv uintptr
gpUniform2fv uintptr
gpUniform2iv uintptr
gpUniform3fv uintptr
gpUniform3iv uintptr
gpUniform4fv uintptr
gpUniform4iv uintptr
gpUniformMatrix2fv uintptr
gpUniformMatrix3fv uintptr
gpUniformMatrix4fv uintptr
@ -406,16 +409,31 @@ func (c *defaultContext) Uniform2fv(location int32, value []float32) {
runtime.KeepAlive(value)
}
func (c *defaultContext) Uniform2iv(location int32, value []int32) {
purego.SyscallN(c.gpUniform2iv, uintptr(location), uintptr(len(value)/2), uintptr(unsafe.Pointer(&value[0])))
runtime.KeepAlive(value)
}
func (c *defaultContext) Uniform3fv(location int32, value []float32) {
purego.SyscallN(c.gpUniform3fv, uintptr(location), uintptr(len(value)/3), uintptr(unsafe.Pointer(&value[0])))
runtime.KeepAlive(value)
}
func (c *defaultContext) Uniform3iv(location int32, value []int32) {
purego.SyscallN(c.gpUniform3iv, uintptr(location), uintptr(len(value)/3), uintptr(unsafe.Pointer(&value[0])))
runtime.KeepAlive(value)
}
func (c *defaultContext) Uniform4fv(location int32, value []float32) {
purego.SyscallN(c.gpUniform4fv, uintptr(location), uintptr(len(value)/4), uintptr(unsafe.Pointer(&value[0])))
runtime.KeepAlive(value)
}
func (c *defaultContext) Uniform4iv(location int32, value []int32) {
purego.SyscallN(c.gpUniform4iv, uintptr(location), uintptr(len(value)/4), uintptr(unsafe.Pointer(&value[0])))
runtime.KeepAlive(value)
}
func (c *defaultContext) UniformMatrix2fv(location int32, value []float32) {
purego.SyscallN(c.gpUniformMatrix2fv, uintptr(location), uintptr(len(value)/4), 0, uintptr(unsafe.Pointer(&value[0])))
runtime.KeepAlive(value)
@ -652,14 +670,26 @@ func (c *defaultContext) LoadFunctions() error {
if c.gpUniform2fv == 0 {
return errors.New("gl: glUniform2fv is missing")
}
c.gpUniform2iv = c.getProcAddress("glUniform2iv")
if c.gpUniform2iv == 0 {
return errors.New("gl: glUniform2iv is missing")
}
c.gpUniform3fv = c.getProcAddress("glUniform3fv")
if c.gpUniform3fv == 0 {
return errors.New("gl: glUniform3fv is missing")
}
c.gpUniform3iv = c.getProcAddress("glUniform3iv")
if c.gpUniform3iv == 0 {
return errors.New("gl: glUniform3iv is missing")
}
c.gpUniform4fv = c.getProcAddress("glUniform4fv")
if c.gpUniform4fv == 0 {
return errors.New("gl: glUniform4fv is missing")
}
c.gpUniform4iv = c.getProcAddress("glUniform4iv")
if c.gpUniform4iv == 0 {
return errors.New("gl: glUniform4iv is missing")
}
c.gpUniformMatrix2fv = c.getProcAddress("glUniformMatrix2fv")
if c.gpUniformMatrix2fv == 0 {
return errors.New("gl: glUniformMatrix2fv is missing")

View File

@ -287,14 +287,26 @@ func (g *gomobileContext) Uniform2fv(location int32, value []float32) {
g.ctx.Uniform2fv(gl.Uniform{Value: location}, value)
}
func (g *gomobileContext) Uniform2iv(location int32, value []int32) {
g.ctx.Uniform2iv(gl.Uniform{Value: location}, value)
}
func (g *gomobileContext) Uniform3fv(location int32, value []float32) {
g.ctx.Uniform3fv(gl.Uniform{Value: location}, value)
}
func (g *gomobileContext) Uniform3iv(location int32, value []int32) {
g.ctx.Uniform3iv(gl.Uniform{Value: location}, value)
}
func (g *gomobileContext) Uniform4fv(location int32, value []float32) {
g.ctx.Uniform4fv(gl.Uniform{Value: location}, value)
}
func (g *gomobileContext) Uniform4iv(location int32, value []int32) {
g.ctx.Uniform4iv(gl.Uniform{Value: location}, value)
}
func (g *gomobileContext) UniformMatrix2fv(location int32, value []float32) {
g.ctx.UniformMatrix2fv(gl.Uniform{Value: location}, value)
}

View File

@ -83,8 +83,11 @@ type Context interface {
Uniform1i(location int32, v0 int32)
Uniform1iv(location int32, value []int32)
Uniform2fv(location int32, value []float32)
Uniform2iv(location int32, value []int32)
Uniform3fv(location int32, value []float32)
Uniform3iv(location int32, value []int32)
Uniform4fv(location int32, value []float32)
Uniform4iv(location int32, value []int32)
UniformMatrix2fv(location int32, value []float32)
UniformMatrix3fv(location int32, value []float32)
UniformMatrix4fv(location int32, value []float32)

View File

@ -54,6 +54,34 @@ func isModAvailableForConsts(lhs, rhs *shaderir.Expr) bool {
return false
}
func isValidForModOp(lhs, rhs *shaderir.Expr, lhst, rhst shaderir.Type) bool {
isInt := func(s *shaderir.Expr, t shaderir.Type) bool {
if t.Main == shaderir.Int {
return true
}
if s.Const == nil {
return false
}
if s.ConstType == shaderir.ConstTypeInt {
return true
}
if canTruncateToInteger(s.Const) {
return true
}
return false
}
if isInt(lhs, lhst) {
return isInt(rhs, rhst)
}
if lhst.Main == shaderir.IVec2 || lhst.Main == shaderir.IVec3 || lhst.Main == shaderir.IVec4 {
return lhst.Equal(&rhst) || isInt(rhs, rhst)
}
return false
}
func canApplyBinaryOp(lhs, rhs *shaderir.Expr, lhst, rhst shaderir.Type, op shaderir.Op) bool {
if op == shaderir.AndAnd || op == shaderir.OrOr {
return lhst.Main == shaderir.Bool && rhst.Main == shaderir.Bool
@ -289,6 +317,11 @@ func (cs *compileState) parseExpr(block *block, fname string, expr ast.Expr, mar
cs.addError(e.Pos(), fmt.Sprintf("types don't match: %s %s %s", lhst.String(), e.Op, rhst.String()))
return nil, nil, nil, false
}
case shaderir.IVec2, shaderir.IVec3, shaderir.IVec4:
if !canTruncateToInteger(lhs[0].Const) {
cs.addError(e.Pos(), fmt.Sprintf("types don't match: %s %s %s", lhst.String(), e.Op, rhst.String()))
return nil, nil, nil, false
}
case shaderir.Int:
if !canTruncateToInteger(lhs[0].Const) {
cs.addError(e.Pos(), fmt.Sprintf("constant %s truncated to integer", lhs[0].Const.String()))
@ -310,6 +343,11 @@ func (cs *compileState) parseExpr(block *block, fname string, expr ast.Expr, mar
cs.addError(e.Pos(), fmt.Sprintf("types don't match: %s %s %s", lhst.String(), e.Op, rhst.String()))
return nil, nil, nil, false
}
case shaderir.IVec2, shaderir.IVec3, shaderir.IVec4:
if !canTruncateToInteger(rhs[0].Const) {
cs.addError(e.Pos(), fmt.Sprintf("types don't match: %s %s %s", lhst.String(), e.Op, rhst.String()))
return nil, nil, nil, false
}
case shaderir.Int:
if !canTruncateToInteger(rhs[0].Const) {
cs.addError(e.Pos(), fmt.Sprintf("constant %s truncated to integer", rhs[0].Const.String()))
@ -368,9 +406,7 @@ func (cs *compileState) parseExpr(block *block, fname string, expr ast.Expr, mar
// For `%`, both types must be deducible to integers.
if op == shaderir.ModOp {
// TODO: What about ivec?
if lhst.Main != shaderir.Int && (lhs[0].ConstType == shaderir.ConstTypeNone || !canTruncateToInteger(lhs[0].Const)) ||
rhst.Main != shaderir.Int && (rhs[0].ConstType == shaderir.ConstTypeNone || !canTruncateToInteger(rhs[0].Const)) {
if !isValidForModOp(&lhs[0], &rhs[0], lhst, rhst) {
var wrongType shaderir.Type
if lhst.Main != shaderir.Int {
wrongType = lhst
@ -527,6 +563,24 @@ func (cs *compileState) parseExpr(block *block, fname string, expr ast.Expr, mar
return nil, nil, nil, false
}
t = shaderir.Type{Main: shaderir.Vec4}
case shaderir.IVec2F:
if err := checkArgsForVec2BuiltinFunc(args, argts); err != nil {
cs.addError(e.Pos(), err.Error())
return nil, nil, nil, false
}
t = shaderir.Type{Main: shaderir.IVec2}
case shaderir.IVec3F:
if err := checkArgsForVec3BuiltinFunc(args, argts); err != nil {
cs.addError(e.Pos(), err.Error())
return nil, nil, nil, false
}
t = shaderir.Type{Main: shaderir.IVec3}
case shaderir.IVec4F:
if err := checkArgsForVec4BuiltinFunc(args, argts); err != nil {
cs.addError(e.Pos(), err.Error())
return nil, nil, nil, false
}
t = shaderir.Type{Main: shaderir.IVec4}
case shaderir.Mat2F:
if err := checkArgsForMat2BuiltinFunc(args, argts); err != nil {
cs.addError(e.Pos(), err.Error())
@ -901,16 +955,31 @@ func (cs *compileState) parseExpr(block *block, fname string, expr ast.Expr, mar
}
var t shaderir.Type
switch len(e.Sel.Name) {
case 1:
t.Main = shaderir.Float
case 2:
t.Main = shaderir.Vec2
case 3:
t.Main = shaderir.Vec3
case 4:
t.Main = shaderir.Vec4
default:
switch types[0].Main {
case shaderir.Vec2, shaderir.Vec3, shaderir.Vec4:
switch len(e.Sel.Name) {
case 1:
t.Main = shaderir.Float
case 2:
t.Main = shaderir.Vec2
case 3:
t.Main = shaderir.Vec3
case 4:
t.Main = shaderir.Vec4
}
case shaderir.IVec2, shaderir.IVec3, shaderir.IVec4:
switch len(e.Sel.Name) {
case 1:
t.Main = shaderir.Int
case 2:
t.Main = shaderir.IVec2
case 3:
t.Main = shaderir.IVec3
case 4:
t.Main = shaderir.IVec4
}
}
if t.Equal(&shaderir.Type{}) {
cs.addError(e.Pos(), fmt.Sprintf("unexpected swizzling: %s", e.Sel.Name))
return nil, nil, nil, false
}
@ -1064,6 +1133,8 @@ func (cs *compileState) parseExpr(block *block, fname string, expr ast.Expr, mar
switch t.Main {
case shaderir.Vec2, shaderir.Vec3, shaderir.Vec4:
typ = shaderir.Type{Main: shaderir.Float}
case shaderir.IVec2, shaderir.IVec3, shaderir.IVec4:
typ = shaderir.Type{Main: shaderir.Int}
case shaderir.Mat2:
typ = shaderir.Type{Main: shaderir.Vec2}
case shaderir.Mat3:
@ -1099,11 +1170,11 @@ func isValidSwizzling(swizzling string, t shaderir.Type) bool {
}
switch t.Main {
case shaderir.Vec2:
case shaderir.Vec2, shaderir.IVec2:
return !strings.ContainsAny(swizzling, "zwbarq")
case shaderir.Vec3:
case shaderir.Vec3, shaderir.IVec3:
return !strings.ContainsAny(swizzling, "waq")
case shaderir.Vec4:
case shaderir.Vec4, shaderir.IVec4:
return true
default:
return false

View File

@ -104,9 +104,15 @@ func (cs *compileState) parseStmt(block *block, fname string, stmt ast.Stmt, inP
}
} else {
switch lts[0].Main {
case shaderir.Int:
if !cs.forceToInt(stmt, &rhs[0]) {
return nil, false
case shaderir.Int, shaderir.IVec2, shaderir.IVec3, shaderir.IVec4:
if rts[0].Main != shaderir.Int {
if !rts[0].Equal(&shaderir.Type{}) {
cs.addError(stmt.Pos(), fmt.Sprintf("invalid operation: mismatched types %s and %s", lts[0].String(), rts[0].String()))
return nil, false
}
if !cs.forceToInt(stmt, &rhs[0]) {
return nil, false
}
}
case shaderir.Float:
if rhs[0].Const != nil &&
@ -151,7 +157,7 @@ func (cs *compileState) parseStmt(block *block, fname string, stmt ast.Stmt, inP
}
}
if op == shaderir.ModOp && lts[0].Main != shaderir.Int {
if op == shaderir.ModOp && lts[0].Main != shaderir.Int && lts[0].Main != shaderir.IVec2 && lts[0].Main != shaderir.IVec3 && lts[0].Main != shaderir.IVec4 {
cs.addError(stmt.Pos(), fmt.Sprintf("invalid operation: operator %% not defined on %s", lts[0].String()))
return nil, false
}

View File

@ -974,6 +974,14 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
}`)); err != nil {
t.Error(err)
}
if _, err := compileToIR([]byte(`package main
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
a := ivec2(1) + 2
return vec4(a.xxyy)
}`)); err != nil {
t.Error(err)
}
if _, err := compileToIR([]byte(`package main
@ -983,6 +991,14 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
}`)); err != nil {
t.Error(err)
}
if _, err := compileToIR([]byte(`package main
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
a := ivec2(1) + 2.1
return vec4(a.xxyy)
}`)); err == nil {
t.Errorf("error must be non-nil but was nil")
}
if _, err := compileToIR([]byte(`package main
@ -992,6 +1008,14 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
}`)); err == nil {
t.Errorf("error must be non-nil but was nil")
}
if _, err := compileToIR([]byte(`package main
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
a := ivec2(1) % 2
return vec4(a.xxyy)
}`)); err != nil {
t.Error(err)
}
if _, err := compileToIR([]byte(`package main
@ -1001,6 +1025,14 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
}`)); err == nil {
t.Errorf("error must be non-nil but was nil")
}
if _, err := compileToIR([]byte(`package main
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
a := ivec2(1) % 2.1
return vec4(a.xxyy)
}`)); err == nil {
t.Errorf("error must be non-nil but was nil")
}
if _, err := compileToIR([]byte(`package main
@ -1011,6 +1043,15 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
}`)); err != nil {
t.Error(err)
}
if _, err := compileToIR([]byte(`package main
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
a := ivec2(1)
a += 2
return vec4(a.xxyy)
}`)); err != nil {
t.Error(err)
}
if _, err := compileToIR([]byte(`package main
@ -1021,6 +1062,15 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
}`)); err != nil {
t.Error(err)
}
if _, err := compileToIR([]byte(`package main
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
a := ivec2(1)
a += 2.1
return vec4(a.xxyy)
}`)); err == nil {
t.Errorf("error must be non-nil but was nil")
}
if _, err := compileToIR([]byte(`package main
@ -1031,6 +1081,15 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
}`)); err == nil {
t.Errorf("error must be non-nil but was nil")
}
if _, err := compileToIR([]byte(`package main
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
a := ivec2(1)
a %= 2
return vec4(a.xxyy)
}`)); err != nil {
t.Error(err)
}
if _, err := compileToIR([]byte(`package main
@ -1038,6 +1097,15 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
a := vec2(1)
a %= 2.1
return a.xxyy
}`)); err == nil {
t.Errorf("error must be non-nil but was nil")
}
if _, err := compileToIR([]byte(`package main
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
a := ivec2(1)
a %= 2.1
return vec4(a.xxyy)
}`)); err == nil {
t.Errorf("error must be non-nil but was nil")
}
@ -1054,14 +1122,37 @@ func TestSyntaxOperatorMultiply(t *testing.T) {
{stmt: "a := 1 * vec2(2); _ = a", err: false},
{stmt: "a := int(1) * vec2(2); _ = a", err: true},
{stmt: "a := 1.0 * vec2(2); _ = a", err: false},
{stmt: "a := 1.1 * vec2(2); _ = a", err: false},
{stmt: "a := 1 + vec2(2); _ = a", err: false},
{stmt: "a := int(1) + vec2(2); _ = a", err: true},
{stmt: "a := 1.0 / vec2(2); _ = a", err: false},
{stmt: "a := 1.1 / vec2(2); _ = a", err: false},
{stmt: "a := 1.0 + vec2(2); _ = a", err: false},
{stmt: "a := 1.1 + vec2(2); _ = a", err: false},
{stmt: "a := 1 * vec3(2); _ = a", err: false},
{stmt: "a := 1.0 * vec3(2); _ = a", err: false},
{stmt: "a := 1.1 * vec3(2); _ = a", err: false},
{stmt: "a := 1 * vec4(2); _ = a", err: false},
{stmt: "a := 1.0 * vec4(2); _ = a", err: false},
{stmt: "a := 1.1 * vec4(2); _ = a", err: false},
{stmt: "a := 1 * ivec2(2); _ = a", err: false},
{stmt: "a := int(1) * ivec2(2); _ = a", err: false},
{stmt: "a := 1.0 * ivec2(2); _ = a", err: false},
{stmt: "a := 1.1 * ivec2(2); _ = a", err: true},
{stmt: "a := 1 + ivec2(2); _ = a", err: false},
{stmt: "a := int(1) + ivec2(2); _ = a", err: false},
{stmt: "a := 1.0 / ivec2(2); _ = a", err: false},
{stmt: "a := 1.1 / ivec2(2); _ = a", err: true},
{stmt: "a := 1.0 + ivec2(2); _ = a", err: false},
{stmt: "a := 1.1 + ivec2(2); _ = a", err: true},
{stmt: "a := 1 * ivec3(2); _ = a", err: false},
{stmt: "a := 1.0 * ivec3(2); _ = a", err: false},
{stmt: "a := 1.1 * ivec3(2); _ = a", err: true},
{stmt: "a := 1 * ivec4(2); _ = a", err: false},
{stmt: "a := 1.0 * ivec4(2); _ = a", err: false},
{stmt: "a := 1.1 * ivec4(2); _ = a", err: true},
{stmt: "a := 1 * mat2(2); _ = a", err: false},
{stmt: "a := 1.0 * mat2(2); _ = a", err: false},
{stmt: "a := float(1.0) / mat2(2); _ = a", err: true},
@ -1072,30 +1163,67 @@ func TestSyntaxOperatorMultiply(t *testing.T) {
{stmt: "a := 1.0 * mat3(2); _ = a", err: false},
{stmt: "a := 1 * mat4(2); _ = a", err: false},
{stmt: "a := 1.0 * mat4(2); _ = a", err: false},
{stmt: "a := vec2(1) * 2; _ = a", err: false},
{stmt: "a := vec2(1) * 2.0; _ = a", err: false},
{stmt: "a := vec2(1) * 2.1; _ = a", err: false},
{stmt: "a := vec2(1) / 2.0; _ = a", err: false},
{stmt: "a := vec2(1) / 2.1; _ = a", err: false},
{stmt: "a := vec2(1) + 2.0; _ = a", err: false},
{stmt: "a := vec2(1) + 2.1; _ = a", err: false},
{stmt: "a := vec2(1) * int(2); _ = a", err: true},
{stmt: "a := vec2(1) * vec2(2); _ = a", err: false},
{stmt: "a := vec2(1) + vec2(2); _ = a", err: false},
{stmt: "a := vec2(1) * vec3(2); _ = a", err: true},
{stmt: "a := vec2(1) * vec4(2); _ = a", err: true},
{stmt: "a := vec2(1) * ivec2(2); _ = a", err: true},
{stmt: "a := vec2(1) + ivec2(2); _ = a", err: true},
{stmt: "a := vec2(1) * ivec3(2); _ = a", err: true},
{stmt: "a := vec2(1) * ivec4(2); _ = a", err: true},
{stmt: "a := vec2(1) * mat2(2); _ = a", err: false},
{stmt: "a := vec2(1) + mat2(2); _ = a", err: true},
{stmt: "a := vec2(1) * mat3(2); _ = a", err: true},
{stmt: "a := vec2(1) * mat4(2); _ = a", err: true},
{stmt: "a := ivec2(1) * 2; _ = a", err: false},
{stmt: "a := ivec2(1) * 2.0; _ = a", err: false},
{stmt: "a := ivec2(1) * 2.1; _ = a", err: true},
{stmt: "a := ivec2(1) / 2.0; _ = a", err: false},
{stmt: "a := ivec2(1) / 2.1; _ = a", err: true},
{stmt: "a := ivec2(1) + 2.0; _ = a", err: false},
{stmt: "a := ivec2(1) + 2.1; _ = a", err: true},
{stmt: "a := ivec2(1) * int(2); _ = a", err: false},
{stmt: "a := ivec2(1) * vec2(2); _ = a", err: true},
{stmt: "a := ivec2(1) + vec2(2); _ = a", err: true},
{stmt: "a := ivec2(1) * vec3(2); _ = a", err: true},
{stmt: "a := ivec2(1) * vec4(2); _ = a", err: true},
{stmt: "a := ivec2(1) * ivec2(2); _ = a", err: false},
{stmt: "a := ivec2(1) + ivec2(2); _ = a", err: false},
{stmt: "a := ivec2(1) * ivec3(2); _ = a", err: true},
{stmt: "a := ivec2(1) * ivec4(2); _ = a", err: true},
{stmt: "a := ivec2(1) * mat2(2); _ = a", err: true},
{stmt: "a := ivec2(1) + mat2(2); _ = a", err: true},
{stmt: "a := ivec2(1) * mat3(2); _ = a", err: true},
{stmt: "a := ivec2(1) * mat4(2); _ = a", err: true},
{stmt: "a := mat2(1) * 2; _ = a", err: false},
{stmt: "a := mat2(1) * 2.0; _ = a", err: false},
{stmt: "a := mat2(1) * 2.1; _ = a", err: false},
{stmt: "a := mat2(1) / 2.0; _ = a", err: false},
{stmt: "a := mat2(1) / 2.1; _ = a", err: false},
{stmt: "a := mat2(1) / float(2); _ = a", err: false},
{stmt: "a := mat2(1) * int(2); _ = a", err: true},
{stmt: "a := mat2(1) + 2.0; _ = a", err: true},
{stmt: "a := mat2(1) + 2.1; _ = a", err: true},
{stmt: "a := mat2(1) + float(2); _ = a", err: true},
{stmt: "a := mat2(1) * vec2(2); _ = a", err: false},
{stmt: "a := mat2(1) + vec2(2); _ = a", err: true},
{stmt: "a := mat2(1) * vec3(2); _ = a", err: true},
{stmt: "a := mat2(1) * vec4(2); _ = a", err: true},
{stmt: "a := mat2(1) * ivec2(2); _ = a", err: true},
{stmt: "a := mat2(1) + ivec2(2); _ = a", err: true},
{stmt: "a := mat2(1) * ivec3(2); _ = a", err: true},
{stmt: "a := mat2(1) * ivec4(2); _ = a", err: true},
{stmt: "a := mat2(1) * mat2(2); _ = a", err: false},
{stmt: "a := mat2(1) / mat2(2); _ = a", err: true},
{stmt: "a := mat2(1) * mat3(2); _ = a", err: true},
@ -1117,6 +1245,8 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
}
}
// TODO
// Issue #1971
func TestSyntaxOperatorMultiplyAssign(t *testing.T) {
cases := []struct {
@ -1135,6 +1265,9 @@ func TestSyntaxOperatorMultiplyAssign(t *testing.T) {
{stmt: "a := 1.0; a *= vec2(2)", err: true},
{stmt: "a := 1.0; a *= vec3(2)", err: true},
{stmt: "a := 1.0; a *= vec4(2)", err: true},
{stmt: "a := 1.0; a *= ivec2(2)", err: true},
{stmt: "a := 1.0; a *= ivec3(2)", err: true},
{stmt: "a := 1.0; a *= ivec4(2)", err: true},
{stmt: "a := 1.0; a *= mat2(2)", err: true},
{stmt: "a := 1.0; a *= mat3(2)", err: true},
{stmt: "a := 1.0; a *= mat4(2)", err: true},
@ -1156,12 +1289,43 @@ func TestSyntaxOperatorMultiplyAssign(t *testing.T) {
{stmt: "a := vec2(1); a += vec2(2)", err: false},
{stmt: "a := vec2(1); a *= vec3(2)", err: true},
{stmt: "a := vec2(1); a *= vec4(2)", err: true},
{stmt: "a := vec2(1); a *= ivec2(2)", err: true},
{stmt: "a := vec2(1); a += ivec2(2)", err: true},
{stmt: "a := vec2(1); a *= ivec3(2)", err: true},
{stmt: "a := vec2(1); a *= ivec4(2)", err: true},
{stmt: "a := vec2(1); a *= mat2(2)", err: false},
{stmt: "a := vec2(1); a += mat2(2)", err: true},
{stmt: "a := vec2(1); a /= mat2(2)", err: true},
{stmt: "a := vec2(1); a *= mat3(2)", err: true},
{stmt: "a := vec2(1); a *= mat4(2)", err: true},
{stmt: "a := ivec2(1); a *= 2", err: false},
{stmt: "a := ivec2(1); a *= 2.0", err: false},
{stmt: "const c = 2; a := ivec2(1); a *= c", err: false},
{stmt: "const c = 2.0; a := ivec2(1); a *= c", err: false},
{stmt: "const c int = 2; a := ivec2(1); a *= c", err: false},
{stmt: "const c int = 2.0; a := ivec2(1); a *= c", err: false},
{stmt: "const c float = 2; a := ivec2(1); a *= c", err: true},
{stmt: "const c float = 2.0; a := ivec2(1); a *= c", err: true},
{stmt: "a := ivec2(1); a /= 2.0", err: false},
{stmt: "a := ivec2(1); a += 2.0", err: false},
{stmt: "a := ivec2(1); a *= int(2)", err: false},
{stmt: "a := ivec2(1); a *= float(2)", err: true},
{stmt: "a := ivec2(1); a /= float(2)", err: true},
{stmt: "a := ivec2(1); a *= vec2(2)", err: true},
{stmt: "a := ivec2(1); a += vec2(2)", err: true},
{stmt: "a := ivec2(1); a *= vec3(2)", err: true},
{stmt: "a := ivec2(1); a *= vec4(2)", err: true},
{stmt: "a := ivec2(1); a *= ivec2(2)", err: false},
{stmt: "a := ivec2(1); a += ivec2(2)", err: false},
{stmt: "a := ivec2(1); a *= ivec3(2)", err: true},
{stmt: "a := ivec2(1); a *= ivec4(2)", err: true},
{stmt: "a := ivec2(1); a *= mat2(2)", err: true},
{stmt: "a := ivec2(1); a += mat2(2)", err: true},
{stmt: "a := ivec2(1); a /= mat2(2)", err: true},
{stmt: "a := ivec2(1); a *= mat3(2)", err: true},
{stmt: "a := ivec2(1); a *= mat4(2)", err: true},
{stmt: "a := mat2(1); a *= 2", err: false},
{stmt: "a := mat2(1); a *= 2.0", err: false},
{stmt: "const c = 2; a := mat2(1); a *= c", err: false},
@ -1179,6 +1343,10 @@ func TestSyntaxOperatorMultiplyAssign(t *testing.T) {
{stmt: "a := mat2(1); a += vec2(2)", err: true},
{stmt: "a := mat2(1); a *= vec3(2)", err: true},
{stmt: "a := mat2(1); a *= vec4(2)", err: true},
{stmt: "a := mat2(1); a *= ivec2(2)", err: true},
{stmt: "a := mat2(1); a += ivec2(2)", err: true},
{stmt: "a := mat2(1); a *= ivec3(2)", err: true},
{stmt: "a := mat2(1); a *= ivec4(2)", err: true},
{stmt: "a := mat2(1); a *= mat2(2)", err: false},
{stmt: "a := mat2(1); a += mat2(2)", err: false},
{stmt: "a := mat2(1); a /= mat2(2)", err: true},
@ -1437,9 +1605,12 @@ func TestSyntaxConstructorFuncType(t *testing.T) {
{stmt: "i := 1.0; a := vec2(i); _ = a", err: false},
{stmt: "a := vec2(vec2(1)); _ = a", err: false},
{stmt: "a := vec2(vec3(1)); _ = a", err: true},
{stmt: "a := vec2(ivec2(1)); _ = a", err: false},
{stmt: "a := vec2(ivec3(1)); _ = a", err: true},
{stmt: "a := vec2(1, 1); _ = a", err: false},
{stmt: "a := vec2(1.0, 1.0); _ = a", err: false},
{stmt: "a := vec2(1.1, 1.1); _ = a", err: false},
{stmt: "i := 1; a := vec2(i, i); _ = a", err: false},
{stmt: "i := 1.0; a := vec2(i, i); _ = a", err: false},
{stmt: "a := vec2(vec2(1), 1); _ = a", err: true},
@ -1449,18 +1620,25 @@ func TestSyntaxConstructorFuncType(t *testing.T) {
{stmt: "a := vec3(1); _ = a", err: false},
{stmt: "a := vec3(1.0); _ = a", err: false},
{stmt: "a := vec3(1.1); _ = a", err: false},
{stmt: "i := 1; a := vec3(i); _ = a", err: false},
{stmt: "i := 1.0; a := vec3(i); _ = a", err: false},
{stmt: "a := vec3(vec3(1)); _ = a", err: false},
{stmt: "a := vec3(vec2(1)); _ = a", err: true},
{stmt: "a := vec3(vec4(1)); _ = a", err: true},
{stmt: "a := vec3(ivec3(1)); _ = a", err: false},
{stmt: "a := vec3(ivec2(1)); _ = a", err: true},
{stmt: "a := vec3(ivec4(1)); _ = a", err: true},
{stmt: "a := vec3(1, 1, 1); _ = a", err: false},
{stmt: "a := vec3(1.0, 1.0, 1.0); _ = a", err: false},
{stmt: "a := vec3(1.1, 1.1, 1.1); _ = a", err: false},
{stmt: "i := 1; a := vec3(i, i, i); _ = a", err: false},
{stmt: "i := 1.0; a := vec3(i, i, i); _ = a", err: false},
{stmt: "a := vec3(vec2(1), 1); _ = a", err: false},
{stmt: "a := vec3(1, vec2(1)); _ = a", err: false},
{stmt: "a := vec3(ivec2(1), 1); _ = a", err: false},
{stmt: "a := vec3(1, ivec2(1)); _ = a", err: false},
{stmt: "a := vec3(vec3(1), 1); _ = a", err: true},
{stmt: "a := vec3(1, vec3(1)); _ = a", err: true},
{stmt: "a := vec3(vec3(1), vec3(1), vec3(1)); _ = a", err: true},
@ -1473,32 +1651,122 @@ func TestSyntaxConstructorFuncType(t *testing.T) {
{stmt: "a := vec4(vec4(1)); _ = a", err: false},
{stmt: "a := vec4(vec2(1)); _ = a", err: true},
{stmt: "a := vec4(vec3(1)); _ = a", err: true},
{stmt: "a := vec4(ivec4(1)); _ = a", err: false},
{stmt: "a := vec4(ivec2(1)); _ = a", err: true},
{stmt: "a := vec4(ivec3(1)); _ = a", err: true},
{stmt: "a := vec4(1, 1, 1, 1); _ = a", err: false},
{stmt: "a := vec4(1.0, 1.0, 1.0, 1.0); _ = a", err: false},
{stmt: "a := vec4(1.1, 1.1, 1.1, 1.1); _ = a", err: false},
{stmt: "i := 1; a := vec4(i, i, i, i); _ = a", err: false},
{stmt: "i := 1.0; a := vec4(i, i, i, i); _ = a", err: false},
{stmt: "a := vec4(vec2(1), 1, 1); _ = a", err: false},
{stmt: "a := vec4(1, vec2(1), 1); _ = a", err: false},
{stmt: "a := vec4(ivec2(1), 1, 1); _ = a", err: false},
{stmt: "a := vec4(1, ivec2(1), 1); _ = a", err: false},
{stmt: "a := vec4(1, 1, vec2(1)); _ = a", err: false},
{stmt: "a := vec4(vec2(1), vec2(1)); _ = a", err: false},
{stmt: "a := vec4(ivec2(1), ivec2(1)); _ = a", err: false},
{stmt: "a := vec4(vec3(1), 1); _ = a", err: false},
{stmt: "a := vec4(1, vec3(1)); _ = a", err: false},
{stmt: "a := vec4(ivec3(1), 1); _ = a", err: false},
{stmt: "a := vec4(1, ivec3(1)); _ = a", err: false},
{stmt: "a := vec4(vec4(1), 1); _ = a", err: true},
{stmt: "a := vec4(1, vec4(1)); _ = a", err: true},
{stmt: "a := vec4(vec4(1), vec4(1), vec4(1), vec4(1)); _ = a", err: true},
{stmt: "a := vec4(1, 1, 1, 1, 1); _ = a", err: true},
{stmt: "a := ivec2(1); _ = a", err: false},
{stmt: "a := ivec2(1.0); _ = a", err: false},
{stmt: "i := 1; a := ivec2(i); _ = a", err: false},
{stmt: "i := 1.0; a := ivec2(i); _ = a", err: false},
{stmt: "a := ivec2(vec2(1)); _ = a", err: false},
{stmt: "a := ivec2(vec3(1)); _ = a", err: true},
{stmt: "a := ivec2(ivec2(1)); _ = a", err: false},
{stmt: "a := ivec2(ivec3(1)); _ = a", err: true},
{stmt: "a := ivec2(1, 1); _ = a", err: false},
{stmt: "a := ivec2(1.0, 1.0); _ = a", err: false},
{stmt: "i := 1; a := ivec2(i, i); _ = a", err: false},
{stmt: "i := 1.0; a := ivec2(i, i); _ = a", err: false},
{stmt: "a := ivec2(vec2(1), 1); _ = a", err: true},
{stmt: "a := ivec2(1, vec2(1)); _ = a", err: true},
{stmt: "a := ivec2(ivec2(1), 1); _ = a", err: true},
{stmt: "a := ivec2(1, ivec2(1)); _ = a", err: true},
{stmt: "a := ivec2(ivec2(1), ivec2(1)); _ = a", err: true},
{stmt: "a := ivec2(1, 1, 1); _ = a", err: true},
{stmt: "a := ivec3(1); _ = a", err: false},
{stmt: "a := ivec3(1.0); _ = a", err: false},
{stmt: "a := ivec3(1.1); _ = a", err: false},
{stmt: "i := 1; a := ivec3(i); _ = a", err: false},
{stmt: "i := 1.0; a := ivec3(i); _ = a", err: false},
{stmt: "a := ivec3(vec3(1)); _ = a", err: false},
{stmt: "a := ivec3(vec2(1)); _ = a", err: true},
{stmt: "a := ivec3(vec4(1)); _ = a", err: true},
{stmt: "a := ivec3(ivec3(1)); _ = a", err: false},
{stmt: "a := ivec3(ivec2(1)); _ = a", err: true},
{stmt: "a := ivec3(ivec4(1)); _ = a", err: true},
{stmt: "a := ivec3(1, 1, 1); _ = a", err: false},
{stmt: "a := ivec3(1.0, 1.0, 1.0); _ = a", err: false},
{stmt: "a := ivec3(1.1, 1.1, 1.1); _ = a", err: false},
{stmt: "i := 1; a := ivec3(i, i, i); _ = a", err: false},
{stmt: "i := 1.0; a := ivec3(i, i, i); _ = a", err: false},
{stmt: "a := ivec3(vec2(1), 1); _ = a", err: false},
{stmt: "a := ivec3(1, vec2(1)); _ = a", err: false},
{stmt: "a := ivec3(ivec2(1), 1); _ = a", err: false},
{stmt: "a := ivec3(1, ivec2(1)); _ = a", err: false},
{stmt: "a := ivec3(vec3(1), 1); _ = a", err: true},
{stmt: "a := ivec3(1, vec3(1)); _ = a", err: true},
{stmt: "a := ivec3(vec3(1), vec3(1), vec3(1)); _ = a", err: true},
{stmt: "a := ivec3(1, 1, 1, 1); _ = a", err: true},
{stmt: "a := ivec4(1); _ = a", err: false},
{stmt: "a := ivec4(1.0); _ = a", err: false},
{stmt: "i := 1; a := ivec4(i); _ = a", err: false},
{stmt: "i := 1.0; a := ivec4(i); _ = a", err: false},
{stmt: "a := ivec4(vec4(1)); _ = a", err: false},
{stmt: "a := ivec4(vec2(1)); _ = a", err: true},
{stmt: "a := ivec4(vec3(1)); _ = a", err: true},
{stmt: "a := ivec4(ivec4(1)); _ = a", err: false},
{stmt: "a := ivec4(ivec2(1)); _ = a", err: true},
{stmt: "a := ivec4(ivec3(1)); _ = a", err: true},
{stmt: "a := ivec4(1, 1, 1, 1); _ = a", err: false},
{stmt: "a := ivec4(1.0, 1.0, 1.0, 1.0); _ = a", err: false},
{stmt: "a := ivec4(1.1, 1.1, 1.1, 1.1); _ = a", err: false},
{stmt: "i := 1; a := ivec4(i, i, i, i); _ = a", err: false},
{stmt: "i := 1.0; a := ivec4(i, i, i, i); _ = a", err: false},
{stmt: "a := ivec4(vec2(1), 1, 1); _ = a", err: false},
{stmt: "a := ivec4(1, vec2(1), 1); _ = a", err: false},
{stmt: "a := ivec4(1, 1, vec2(1)); _ = a", err: false},
{stmt: "a := ivec4(ivec2(1), 1, 1); _ = a", err: false},
{stmt: "a := ivec4(1, ivec2(1), 1); _ = a", err: false},
{stmt: "a := ivec4(1, 1, ivec2(1)); _ = a", err: false},
{stmt: "a := ivec4(vec2(1), vec2(1)); _ = a", err: false},
{stmt: "a := ivec4(ivec2(1), ivec2(1)); _ = a", err: false},
{stmt: "a := ivec4(vec3(1), 1); _ = a", err: false},
{stmt: "a := ivec4(1, vec3(1)); _ = a", err: false},
{stmt: "a := ivec4(ivec3(1), 1); _ = a", err: false},
{stmt: "a := ivec4(1, ivec3(1)); _ = a", err: false},
{stmt: "a := ivec4(vec4(1), 1); _ = a", err: true},
{stmt: "a := ivec4(1, vec4(1)); _ = a", err: true},
{stmt: "a := ivec4(vec4(1), vec4(1), vec4(1), vec4(1)); _ = a", err: true},
{stmt: "a := ivec4(1, 1, 1, 1, 1); _ = a", err: true},
{stmt: "a := mat2(1); _ = a", err: false},
{stmt: "a := mat2(1.0); _ = a", err: false},
{stmt: "i := 1; a := mat2(i); _ = a", err: false},
{stmt: "i := 1.0; a := mat2(i); _ = a", err: false},
{stmt: "a := mat2(mat2(1)); _ = a", err: false},
{stmt: "a := mat2(vec2(1)); _ = a", err: true},
{stmt: "a := mat2(ivec2(1)); _ = a", err: true},
{stmt: "a := mat2(mat3(1)); _ = a", err: true},
{stmt: "a := mat2(mat4(1)); _ = a", err: true},
{stmt: "a := mat2(vec2(1), vec2(1)); _ = a", err: false},
{stmt: "a := mat2(ivec2(1), ivec2(1)); _ = a", err: false},
{stmt: "a := mat2(1, 1); _ = a", err: true},
{stmt: "a := mat2(1, vec2(1)); _ = a", err: true},
{stmt: "a := mat2(vec2(1), vec3(1)); _ = a", err: true},
@ -1521,10 +1789,12 @@ func TestSyntaxConstructorFuncType(t *testing.T) {
{stmt: "i := 1.0; a := mat3(i); _ = a", err: false},
{stmt: "a := mat3(mat3(1)); _ = a", err: false},
{stmt: "a := mat3(vec2(1)); _ = a", err: true},
{stmt: "a := mat3(ivec2(1)); _ = a", err: true},
{stmt: "a := mat3(mat2(1)); _ = a", err: true},
{stmt: "a := mat3(mat4(1)); _ = a", err: true},
{stmt: "a := mat3(vec3(1), vec3(1), vec3(1)); _ = a", err: false},
{stmt: "a := mat3(ivec3(1), ivec3(1), ivec3(1)); _ = a", err: false},
{stmt: "a := mat3(1, 1, 1); _ = a", err: true},
{stmt: "a := mat3(1, 1, vec3(1)); _ = a", err: true},
{stmt: "a := mat3(vec3(1), vec3(1), vec4(1)); _ = a", err: true},
@ -1547,10 +1817,12 @@ func TestSyntaxConstructorFuncType(t *testing.T) {
{stmt: "i := 1.0; a := mat4(i); _ = a", err: false},
{stmt: "a := mat4(mat4(1)); _ = a", err: false},
{stmt: "a := mat4(vec2(1)); _ = a", err: true},
{stmt: "a := mat4(ivec2(1)); _ = a", err: true},
{stmt: "a := mat4(mat2(1)); _ = a", err: true},
{stmt: "a := mat4(mat3(1)); _ = a", err: true},
{stmt: "a := mat4(vec4(1), vec4(1), vec4(1), vec4(1)); _ = a", err: false},
{stmt: "a := mat4(ivec4(1), ivec4(1), ivec4(1), ivec4(1)); _ = a", err: false},
{stmt: "a := mat4(1, 1, 1, 1); _ = a", err: true},
{stmt: "a := mat4(1, 1, 1, vec4(1)); _ = a", err: true},
{stmt: "a := mat4(vec4(1), vec4(1), vec4(1), vec2(1)); _ = a", err: true},
@ -1636,6 +1908,9 @@ func TestSyntaxBuiltinFuncSingleArgType(t *testing.T) {
{stmt: "a := {{.Func}}(vec2(1)); _ = a", err: false},
{stmt: "a := {{.Func}}(vec3(1)); _ = a", err: false},
{stmt: "a := {{.Func}}(vec4(1)); _ = a", err: false},
{stmt: "a := {{.Func}}(ivec2(1)); _ = a", err: true},
{stmt: "a := {{.Func}}(ivec3(1)); _ = a", err: true},
{stmt: "a := {{.Func}}(ivec4(1)); _ = a", err: true},
{stmt: "a := {{.Func}}(mat2(1)); _ = a", err: true},
{stmt: "a := {{.Func}}(mat3(1)); _ = a", err: true},
{stmt: "a := {{.Func}}(mat4(1)); _ = a", err: true},
@ -1714,6 +1989,8 @@ func TestSyntaxBuiltinFuncDoubleArgsType(t *testing.T) {
{stmt: "a := {{.Func}}(vec4(1), vec3(1)); _ = a", err: true},
{stmt: "a := {{.Func}}(vec4(1), vec4(1)); _ = a", err: false},
{stmt: "a := {{.Func}}(mat2(1), mat2(1)); _ = a", err: true},
{stmt: "a := {{.Func}}(ivec2(1), 1); _ = a", err: true},
{stmt: "a := {{.Func}}(ivec2(1), ivec2(1)); _ = a", err: true},
{stmt: "a := {{.Func}}(1, 1, 1); _ = a", err: true},
}
@ -1759,6 +2036,9 @@ func TestSyntaxBuiltinFuncDoubleArgsType2(t *testing.T) {
{stmt: "a := {{.Func}}(1, vec2(1)); _ = a", err: true},
{stmt: "a := {{.Func}}(1, vec3(1)); _ = a", err: true},
{stmt: "a := {{.Func}}(1, vec4(1)); _ = a", err: true},
{stmt: "a := {{.Func}}(1, ivec2(1)); _ = a", err: true},
{stmt: "a := {{.Func}}(1, ivec3(1)); _ = a", err: true},
{stmt: "a := {{.Func}}(1, ivec4(1)); _ = a", err: true},
{stmt: "a := {{.Func}}(vec2(1), 1); _ = a", err: false}, // The second argument can be a scalar.
{stmt: "a := {{.Func}}(vec2(1), vec2(1)); _ = a", err: false},
{stmt: "a := {{.Func}}(vec2(1), vec3(1)); _ = a", err: true},
@ -1772,6 +2052,8 @@ func TestSyntaxBuiltinFuncDoubleArgsType2(t *testing.T) {
{stmt: "a := {{.Func}}(vec4(1), vec3(1)); _ = a", err: true},
{stmt: "a := {{.Func}}(vec4(1), vec4(1)); _ = a", err: false},
{stmt: "a := {{.Func}}(mat2(1), mat2(1)); _ = a", err: true},
{stmt: "a := {{.Func}}(ivec2(1), 1); _ = a", err: true},
{stmt: "a := {{.Func}}(ivec2(1), ivec2(1)); _ = a", err: true},
{stmt: "a := {{.Func}}(1, 1, 1); _ = a", err: true},
}
@ -1815,6 +2097,9 @@ func TestSyntaxBuiltinFuncStepType(t *testing.T) {
{stmt: "a := step(1, vec2(1)); _ = a", err: false}, // The first argument can be a scalar.
{stmt: "a := step(1, vec3(1)); _ = a", err: false}, // The first argument can be a scalar.
{stmt: "a := step(1, vec4(1)); _ = a", err: false}, // The first argument can be a scalar.
{stmt: "a := step(1, ivec2(1)); _ = a", err: true},
{stmt: "a := step(1, ivec3(1)); _ = a", err: true},
{stmt: "a := step(1, ivec4(1)); _ = a", err: true},
{stmt: "a := step(vec2(1), 1); _ = a", err: true},
{stmt: "a := step(vec2(1), vec2(1)); _ = a", err: false},
{stmt: "a := step(vec2(1), vec3(1)); _ = a", err: true},
@ -1828,6 +2113,7 @@ func TestSyntaxBuiltinFuncStepType(t *testing.T) {
{stmt: "a := step(vec4(1), vec3(1)); _ = a", err: true},
{stmt: "a := step(vec4(1), vec4(1)); _ = a", err: false},
{stmt: "a := step(mat2(1), mat2(1)); _ = a", err: true},
{stmt: "a := step(ivec2(1), ivec2(1)); _ = a", err: true},
{stmt: "a := step(1, 1, 1); _ = a", err: true},
}
@ -1879,7 +2165,7 @@ func TestSyntaxBuiltinFuncTripleArgsType(t *testing.T) {
{stmt: "a := {{.Func}}(vec4(1), 1, vec4(1)); _ = a", err: true},
{stmt: "a := {{.Func}}(vec4(1), vec4(1), 1); _ = a", err: true},
{stmt: "a := {{.Func}}(vec4(1), vec4(1), vec4(1)); _ = a", err: false},
{stmt: "a := {{.Func}}(1, 1, 1, 1); _ = a", err: true},
{stmt: "a := {{.Func}}(ivec2(1), ivec2(1), ivec2(1)); _ = a", err: true},
}
funcs := []string{
@ -1935,6 +2221,7 @@ func TestSyntaxBuiltinFuncClampType(t *testing.T) {
{stmt: "a := clamp(vec4(1), 1, vec4(1)); _ = a", err: true},
{stmt: "a := clamp(vec4(1), vec4(1), 1); _ = a", err: true},
{stmt: "a := clamp(vec4(1), vec4(1), vec4(1)); _ = a", err: false},
{stmt: "a := clamp(ivec2(1), 1, 1); _ = a", err: true},
{stmt: "a := clamp(1, 1, 1, 1); _ = a", err: true},
}
@ -1986,6 +2273,8 @@ func TestSyntaxBuiltinFuncMixType(t *testing.T) {
{stmt: "a := mix(vec4(1), 1, vec4(1)); _ = a", err: true},
{stmt: "a := mix(vec4(1), vec4(1), 1); _ = a", err: false}, // The thrid argument can be a float.
{stmt: "a := mix(vec4(1), vec4(1), vec4(1)); _ = a", err: false},
{stmt: "a := mix(ivec2(1), ivec2(1), 1); _ = a", err: true},
{stmt: "a := mix(ivec2(1), ivec2(1), ivec2(1)); _ = a", err: true},
{stmt: "a := mix(1, 1, 1, 1); _ = a", err: true},
}
@ -2039,6 +2328,9 @@ func TestSyntaxBuiltinFuncSmoothstepType(t *testing.T) {
{stmt: "a := smoothstep(vec4(1), 1, vec4(1)); _ = a", err: true},
{stmt: "a := smoothstep(vec4(1), vec4(1), 1); _ = a", err: true},
{stmt: "a := smoothstep(vec4(1), vec4(1), vec4(1)); _ = a", err: false},
{stmt: "a := smoothstep(ivec2(1), 1, 1); _ = a", err: true},
{stmt: "a := smoothstep(1, ivec2(1), 1); _ = a", err: true},
{stmt: "a := smoothstep(1, 1, ivec2(1)); _ = a", err: true},
{stmt: "a := smoothstep(1, 1, 1, 1); _ = a", err: true},
}
@ -2090,6 +2382,7 @@ func TestSyntaxBuiltinFuncRefractType(t *testing.T) {
{stmt: "a := refract(vec4(1), 1, vec4(1)); _ = a", err: true},
{stmt: "a := refract(vec4(1), vec4(1), 1); _ = a", err: false}, // The third argument must be a float.
{stmt: "a := refract(vec4(1), vec4(1), vec4(1)); _ = a", err: true},
{stmt: "a := refract(ivec2(1), ivec2(1), 1); _ = a", err: true},
{stmt: "a := refract(1, 1, 1, 1); _ = a", err: true},
}
@ -2139,6 +2432,7 @@ func TestSyntaxBuiltinFuncCrossType(t *testing.T) {
{stmt: "a := cross(vec4(1), vec3(1)); _ = a", err: true},
{stmt: "a := cross(vec4(1), vec4(1)); _ = a", err: true},
{stmt: "a := cross(mat2(1), mat2(1)); _ = a", err: true},
{stmt: "a := cross(ivec3(1), ivec3(1)); _ = a", err: true},
{stmt: "a := cross(1, 1, 1); _ = a", err: true},
}
@ -2173,6 +2467,9 @@ func TestSyntaxBuiltinFuncTransposeType(t *testing.T) {
{stmt: "a := transpose(vec2(1)); _ = a", err: true},
{stmt: "a := transpose(vec3(1)); _ = a", err: true},
{stmt: "a := transpose(vec4(1)); _ = a", err: true},
{stmt: "a := transpose(ivec2(1)); _ = a", err: true},
{stmt: "a := transpose(ivec3(1)); _ = a", err: true},
{stmt: "a := transpose(ivec4(1)); _ = a", err: true},
{stmt: "a := transpose(mat2(1)); _ = a", err: false},
{stmt: "a := transpose(mat3(1)); _ = a", err: false},
{stmt: "a := transpose(mat4(1)); _ = a", err: false},
@ -2220,6 +2517,8 @@ func TestSyntaxEqual(t *testing.T) {
{stmt: "a, b := false, 1.1; _ = a != b", err: true},
{stmt: "a, b := false, vec2(1); _ = a == b", err: true},
{stmt: "a, b := false, vec2(1); _ = a != b", err: true},
{stmt: "a, b := false, ivec2(1); _ = a == b", err: true},
{stmt: "a, b := false, ivec2(1); _ = a != b", err: true},
{stmt: "a, b := false, mat2(1); _ = a == b", err: true},
{stmt: "a, b := false, mat2(1); _ = a != b", err: true},
@ -2241,6 +2540,8 @@ func TestSyntaxEqual(t *testing.T) {
{stmt: "a, b := 1, 1.1; _ = a != b", err: true},
{stmt: "a, b := 1, vec2(1); _ = a == b", err: true},
{stmt: "a, b := 1, vec2(1); _ = a != b", err: true},
{stmt: "a, b := 1, ivec2(1); _ = a == b", err: true},
{stmt: "a, b := 1, ivec2(1); _ = a != b", err: true},
{stmt: "a, b := 1, mat2(1); _ = a == b", err: true},
{stmt: "a, b := 1, mat2(1); _ = a != b", err: true},
@ -2262,6 +2563,8 @@ func TestSyntaxEqual(t *testing.T) {
{stmt: "a, b := 1.0, 1.1; _ = a != b", err: false},
{stmt: "a, b := 1.0, vec2(1); _ = a == b", err: true},
{stmt: "a, b := 1.0, vec2(1); _ = a != b", err: true},
{stmt: "a, b := 1.0, ivec2(1); _ = a == b", err: true},
{stmt: "a, b := 1.0, ivec2(1); _ = a != b", err: true},
{stmt: "a, b := 1.0, mat2(1); _ = a == b", err: true},
{stmt: "a, b := 1.0, mat2(1); _ = a != b", err: true},
@ -2283,6 +2586,8 @@ func TestSyntaxEqual(t *testing.T) {
{stmt: "a, b := 1.1, 1.1; _ = a != b", err: false},
{stmt: "a, b := 1.1, vec2(1); _ = a == b", err: true},
{stmt: "a, b := 1.1, vec2(1); _ = a != b", err: true},
{stmt: "a, b := 1.1, ivec2(1); _ = a == b", err: true},
{stmt: "a, b := 1.1, ivec2(1); _ = a != b", err: true},
{stmt: "a, b := 1.1, mat2(1); _ = a == b", err: true},
{stmt: "a, b := 1.1, mat2(1); _ = a != b", err: true},
@ -2304,9 +2609,34 @@ func TestSyntaxEqual(t *testing.T) {
{stmt: "a, b := vec2(1), 1.1; _ = a != b", err: true},
{stmt: "a, b := vec2(1), vec2(1); _ = a == b", err: false},
{stmt: "a, b := vec2(1), vec2(1); _ = a != b", err: false},
{stmt: "a, b := vec2(1), ivec2(1); _ = a == b", err: true},
{stmt: "a, b := vec2(1), ivec2(1); _ = a != b", err: true},
{stmt: "a, b := vec2(1), mat2(1); _ = a == b", err: true},
{stmt: "a, b := vec2(1), mat2(1); _ = a != b", err: true},
{stmt: "_ = ivec2(1) == true", err: true},
{stmt: "_ = ivec2(1) != true", err: true},
{stmt: "_ = ivec2(1) == 1", err: true},
{stmt: "_ = ivec2(1) != 1", err: true},
{stmt: "_ = ivec2(1) == 1.0", err: true},
{stmt: "_ = ivec2(1) != 1.0", err: true},
{stmt: "_ = ivec2(1) == 1.1", err: true},
{stmt: "_ = ivec2(1) != 1.1", err: true},
{stmt: "a, b := ivec2(1), true; _ = a == b", err: true},
{stmt: "a, b := ivec2(1), true; _ = a != b", err: true},
{stmt: "a, b := ivec2(1), 1; _ = a == b", err: true},
{stmt: "a, b := ivec2(1), 1; _ = a != b", err: true},
{stmt: "a, b := ivec2(1), 1.0; _ = a == b", err: true},
{stmt: "a, b := ivec2(1), 1.0; _ = a != b", err: true},
{stmt: "a, b := ivec2(1), 1.1; _ = a == b", err: true},
{stmt: "a, b := ivec2(1), 1.1; _ = a != b", err: true},
{stmt: "a, b := ivec2(1), vec2(1); _ = a == b", err: true},
{stmt: "a, b := ivec2(1), vec2(1); _ = a != b", err: true},
{stmt: "a, b := ivec2(1), ivec2(1); _ = a == b", err: false},
{stmt: "a, b := ivec2(1), ivec2(1); _ = a != b", err: false},
{stmt: "a, b := ivec2(1), mat2(1); _ = a == b", err: true},
{stmt: "a, b := ivec2(1), mat2(1); _ = a != b", err: true},
{stmt: "_ = mat2(1) == true", err: true},
{stmt: "_ = mat2(1) != true", err: true},
{stmt: "_ = mat2(1) == 1", err: true},
@ -2325,6 +2655,8 @@ func TestSyntaxEqual(t *testing.T) {
{stmt: "a, b := mat2(1), 1.1; _ = a != b", err: true},
{stmt: "a, b := mat2(1), vec2(1); _ = a == b", err: true},
{stmt: "a, b := mat2(1), vec2(1); _ = a != b", err: true},
{stmt: "a, b := mat2(1), ivec2(1); _ = a == b", err: true},
{stmt: "a, b := mat2(1), ivec2(1); _ = a != b", err: true},
{stmt: "a, b := mat2(1), mat2(1); _ = a == b", err: true}, // Comparing matrices are not allowed.
{stmt: "a, b := mat2(1), mat2(1); _ = a != b", err: true}, // Comparing matrices are not allowed.
@ -2346,6 +2678,8 @@ func TestSyntaxEqual(t *testing.T) {
{stmt: "a, b := false, 1.1; _ = a || b", err: true},
{stmt: "a, b := false, vec2(1); _ = a && b", err: true},
{stmt: "a, b := false, vec2(1); _ = a || b", err: true},
{stmt: "a, b := false, ivec2(1); _ = a && b", err: true},
{stmt: "a, b := false, ivec2(1); _ = a || b", err: true},
{stmt: "a, b := false, mat2(1); _ = a && b", err: true},
{stmt: "a, b := false, mat2(1); _ = a || b", err: true},
@ -2367,6 +2701,8 @@ func TestSyntaxEqual(t *testing.T) {
{stmt: "a, b := 1.0, 1.1; _ = a || b", err: true},
{stmt: "a, b := 1.0, vec2(1); _ = a && b", err: true},
{stmt: "a, b := 1.0, vec2(1); _ = a || b", err: true},
{stmt: "a, b := 1.0, ivec2(1); _ = a && b", err: true},
{stmt: "a, b := 1.0, ivec2(1); _ = a || b", err: true},
{stmt: "a, b := 1.0, mat2(1); _ = a && b", err: true},
{stmt: "a, b := 1.0, mat2(1); _ = a || b", err: true},
}
@ -2453,6 +2789,39 @@ func TestSwizzling(t *testing.T) {
{stmt: "var a vec4; var b vec3 = a.xyy; _ = b", err: false},
{stmt: "var a vec4; var b vec3 = a.xyz; _ = b", err: false},
{stmt: "var a vec4; var b vec4 = a.xyzw; _ = b", err: false},
{stmt: "var a ivec2; var b int = a.x; _ = b", err: false},
{stmt: "var a ivec2; var b int = a.y; _ = b", err: false},
{stmt: "var a ivec2; var b int = a.z; _ = b", err: true},
{stmt: "var a ivec2; var b int = a.w; _ = b", err: true},
{stmt: "var a ivec2; var b ivec2 = a.xy; _ = b", err: false},
{stmt: "var a ivec2; var b ivec3 = a.xyz; _ = b", err: true},
{stmt: "var a ivec2; var b ivec3 = a.xyw; _ = b", err: true},
{stmt: "var a ivec2; var b ivec3 = a.xyy; _ = b", err: false},
{stmt: "var a ivec2; var b ivec3 = a.xyz; _ = b", err: true},
{stmt: "var a ivec2; var b ivec4 = a.xyzw; _ = b", err: true},
{stmt: "var a ivec3; var b int = a.x; _ = b", err: false},
{stmt: "var a ivec3; var b int = a.y; _ = b", err: false},
{stmt: "var a ivec3; var b int = a.z; _ = b", err: false},
{stmt: "var a ivec3; var b int = a.w; _ = b", err: true},
{stmt: "var a ivec3; var b ivec2 = a.xy; _ = b", err: false},
{stmt: "var a ivec3; var b ivec3 = a.xyz; _ = b", err: false},
{stmt: "var a ivec3; var b ivec3 = a.xyw; _ = b", err: true},
{stmt: "var a ivec3; var b ivec3 = a.xyy; _ = b", err: false},
{stmt: "var a ivec3; var b ivec3 = a.xyz; _ = b", err: false},
{stmt: "var a ivec3; var b ivec4 = a.xyzw; _ = b", err: true},
{stmt: "var a ivec4; var b int = a.x; _ = b", err: false},
{stmt: "var a ivec4; var b int = a.y; _ = b", err: false},
{stmt: "var a ivec4; var b int = a.z; _ = b", err: false},
{stmt: "var a ivec4; var b int = a.w; _ = b", err: false},
{stmt: "var a ivec4; var b ivec2 = a.xy; _ = b", err: false},
{stmt: "var a ivec4; var b ivec3 = a.xyz; _ = b", err: false},
{stmt: "var a ivec4; var b ivec3 = a.xyw; _ = b", err: false},
{stmt: "var a ivec4; var b ivec3 = a.xyy; _ = b", err: false},
{stmt: "var a ivec4; var b ivec3 = a.xyz; _ = b", err: false},
{stmt: "var a ivec4; var b ivec4 = a.xyzw; _ = b", err: false},
}
for _, c := range cases {
@ -2482,84 +2851,105 @@ func TestConstType(t *testing.T) {
{stmt: "const a int = false", err: true},
{stmt: "const a float = false", err: true},
{stmt: "const a vec2 = false", err: true},
{stmt: "const a ivec2 = false", err: true},
{stmt: "const a = bool(false)", err: false},
{stmt: "const a bool = bool(false)", err: false},
{stmt: "const a int = bool(false)", err: true},
{stmt: "const a float = bool(false)", err: true},
{stmt: "const a vec2 = bool(false)", err: true},
{stmt: "const a ivec2 = bool(false)", err: true},
{stmt: "const a = int(false)", err: true},
{stmt: "const a bool = int(false)", err: true},
{stmt: "const a int = int(false)", err: true},
{stmt: "const a float = int(false)", err: true},
{stmt: "const a vec2 = int(false)", err: true},
{stmt: "const a ivec2 = int(false)", err: true},
{stmt: "const a = float(false)", err: true},
{stmt: "const a bool = float(false)", err: true},
{stmt: "const a int = float(false)", err: true},
{stmt: "const a float = float(false)", err: true},
{stmt: "const a vec2 = float(false)", err: true},
{stmt: "const a ivec2 = float(false)", err: true},
{stmt: "const a = 1", err: false},
{stmt: "const a bool = 1", err: true},
{stmt: "const a int = 1", err: false},
{stmt: "const a float = 1", err: false},
{stmt: "const a vec2 = 1", err: true},
{stmt: "const a ivec2 = 1", err: true},
{stmt: "const a = int(1)", err: false},
{stmt: "const a bool = int(1)", err: true},
{stmt: "const a int = int(1)", err: false},
{stmt: "const a float = int(1)", err: true},
{stmt: "const a vec2 = int(1)", err: true},
{stmt: "const a ivec2 = int(1)", err: true},
{stmt: "const a = float(1)", err: false},
{stmt: "const a bool = float(1)", err: true},
{stmt: "const a int = float(1)", err: true},
{stmt: "const a float = float(1)", err: false},
{stmt: "const a vec2 = float(1)", err: true},
{stmt: "const a ivec2 = float(1)", err: true},
{stmt: "const a = 1.0", err: false},
{stmt: "const a bool = 1.0", err: true},
{stmt: "const a int = 1.0", err: false},
{stmt: "const a float = 1.0", err: false},
{stmt: "const a vec2 = 1.0", err: true},
{stmt: "const a ivec2 = 1.0", err: true},
{stmt: "const a = int(1.0)", err: false},
{stmt: "const a bool = int(1.0)", err: true},
{stmt: "const a int = int(1.0)", err: false},
{stmt: "const a float = int(1.0)", err: true},
{stmt: "const a vec2 = int(1.0)", err: true},
{stmt: "const a ivec2 = int(1.0)", err: true},
{stmt: "const a = float(1.0)", err: false},
{stmt: "const a bool = float(1.0)", err: true},
{stmt: "const a int = float(1.0)", err: true},
{stmt: "const a float = float(1.0)", err: false},
{stmt: "const a vec2 = float(1.0)", err: true},
{stmt: "const a ivec2 = float(1.0)", err: true},
{stmt: "const a = 1.1", err: false},
{stmt: "const a bool = 1.1", err: true},
{stmt: "const a int = 1.1", err: true},
{stmt: "const a float = 1.1", err: false},
{stmt: "const a vec2 = 1.1", err: true},
{stmt: "const a ivec2 = 1.1", err: true},
{stmt: "const a = int(1.1)", err: true},
{stmt: "const a bool = int(1.1)", err: true},
{stmt: "const a int = int(1.1)", err: true},
{stmt: "const a float = int(1.1)", err: true},
{stmt: "const a vec2 = int(1.1)", err: true},
{stmt: "const a ivec2 = int(1.1)", err: true},
{stmt: "const a = float(1.1)", err: false},
{stmt: "const a bool = float(1.1)", err: true},
{stmt: "const a int = float(1.1)", err: true},
{stmt: "const a float = float(1.1)", err: false},
{stmt: "const a vec2 = float(1.1)", err: true},
{stmt: "const a ivec2 = float(1.1)", err: true},
{stmt: "const a = vec2(0)", err: true},
{stmt: "const a bool = vec2(0)", err: true},
{stmt: "const a int = vec2(0)", err: true},
{stmt: "const a float = vec2(0)", err: true},
{stmt: "const a vec2 = vec2(0)", err: true},
{stmt: "const a ivec2 = vec2(0)", err: true},
{stmt: "const a = ivec2(0)", err: true},
{stmt: "const a bool = ivec2(0)", err: true},
{stmt: "const a int = ivec2(0)", err: true},
{stmt: "const a float = ivec2(0)", err: true},
{stmt: "const a vec2 = ivec2(0)", err: true},
{stmt: "const a ivec2 = ivec2(0)", err: true},
}
for _, c := range cases {

View File

@ -39,6 +39,12 @@ func (cs *compileState) parseType(block *block, fname string, expr ast.Expr) (sh
return shaderir.Type{Main: shaderir.Vec3}, true
case "vec4":
return shaderir.Type{Main: shaderir.Vec4}, true
case "ivec2":
return shaderir.Type{Main: shaderir.IVec2}, true
case "ivec3":
return shaderir.Type{Main: shaderir.IVec3}, true
case "ivec4":
return shaderir.Type{Main: shaderir.IVec4}, true
case "mat2":
return shaderir.Type{Main: shaderir.Mat2}, true
case "mat3":
@ -177,7 +183,7 @@ func checkArgsForVec2BuiltinFunc(args []shaderir.Expr, argts []shaderir.Type) er
if canBeFloatImplicitly(args[0], argts[0]) {
return nil
}
if argts[0].Main == shaderir.Vec2 {
if argts[0].IsVector() && argts[0].VectorElementCount() == 2 {
return nil
}
case 2:
@ -205,14 +211,14 @@ func checkArgsForVec3BuiltinFunc(args []shaderir.Expr, argts []shaderir.Type) er
if canBeFloatImplicitly(args[0], argts[0]) {
return nil
}
if argts[0].Main == shaderir.Vec3 {
if argts[0].IsVector() && argts[0].VectorElementCount() == 3 {
return nil
}
case 2:
if canBeFloatImplicitly(args[0], argts[0]) && argts[1].Main == shaderir.Vec2 {
if canBeFloatImplicitly(args[0], argts[0]) && argts[1].IsVector() && argts[1].VectorElementCount() == 2 {
return nil
}
if argts[0].Main == shaderir.Vec2 && canBeFloatImplicitly(args[1], argts[1]) {
if argts[0].IsVector() && argts[0].VectorElementCount() == 2 && canBeFloatImplicitly(args[1], argts[1]) {
return nil
}
case 3:
@ -240,27 +246,27 @@ func checkArgsForVec4BuiltinFunc(args []shaderir.Expr, argts []shaderir.Type) er
if canBeFloatImplicitly(args[0], argts[0]) {
return nil
}
if argts[0].Main == shaderir.Vec4 {
if argts[0].IsVector() && argts[0].VectorElementCount() == 4 {
return nil
}
case 2:
if canBeFloatImplicitly(args[0], argts[0]) && argts[1].Main == shaderir.Vec3 {
if canBeFloatImplicitly(args[0], argts[0]) && argts[1].IsVector() && argts[1].VectorElementCount() == 3 {
return nil
}
if argts[0].Main == shaderir.Vec2 && argts[1].Main == shaderir.Vec2 {
if argts[0].IsVector() && argts[0].VectorElementCount() == 2 && argts[1].IsVector() && argts[1].VectorElementCount() == 2 {
return nil
}
if argts[0].Main == shaderir.Vec3 && canBeFloatImplicitly(args[1], argts[1]) {
if argts[0].IsVector() && argts[0].VectorElementCount() == 3 && canBeFloatImplicitly(args[1], argts[1]) {
return nil
}
case 3:
if canBeFloatImplicitly(args[0], argts[0]) && canBeFloatImplicitly(args[1], argts[1]) && argts[2].Main == shaderir.Vec2 {
if canBeFloatImplicitly(args[0], argts[0]) && canBeFloatImplicitly(args[1], argts[1]) && argts[2].IsVector() && argts[2].VectorElementCount() == 2 {
return nil
}
if canBeFloatImplicitly(args[0], argts[0]) && argts[1].Main == shaderir.Vec2 && canBeFloatImplicitly(args[2], argts[2]) {
if canBeFloatImplicitly(args[0], argts[0]) && argts[1].IsVector() && argts[1].VectorElementCount() == 2 && canBeFloatImplicitly(args[2], argts[2]) {
return nil
}
if argts[0].Main == shaderir.Vec2 && canBeFloatImplicitly(args[1], argts[1]) && canBeFloatImplicitly(args[2], argts[2]) {
if argts[0].IsVector() && argts[0].VectorElementCount() == 2 && canBeFloatImplicitly(args[1], argts[1]) && canBeFloatImplicitly(args[2], argts[2]) {
return nil
}
case 4:
@ -292,7 +298,7 @@ func checkArgsForMat2BuiltinFunc(args []shaderir.Expr, argts []shaderir.Type) er
return nil
}
case 2:
if argts[0].Main == shaderir.Vec2 && argts[1].Main == shaderir.Vec2 {
if argts[0].IsVector() && argts[0].VectorElementCount() == 2 && argts[1].IsVector() && argts[1].VectorElementCount() == 2 {
return nil
}
case 4:
@ -331,7 +337,9 @@ func checkArgsForMat3BuiltinFunc(args []shaderir.Expr, argts []shaderir.Type) er
return nil
}
case 3:
if argts[0].Main == shaderir.Vec3 && argts[1].Main == shaderir.Vec3 && argts[2].Main == shaderir.Vec3 {
if argts[0].IsVector() && argts[0].VectorElementCount() == 3 &&
argts[1].IsVector() && argts[1].VectorElementCount() == 3 &&
argts[2].IsVector() && argts[2].VectorElementCount() == 3 {
return nil
}
case 9:
@ -370,7 +378,10 @@ func checkArgsForMat4BuiltinFunc(args []shaderir.Expr, argts []shaderir.Type) er
return nil
}
case 4:
if argts[0].Main == shaderir.Vec4 && argts[1].Main == shaderir.Vec4 && argts[2].Main == shaderir.Vec4 && argts[3].Main == shaderir.Vec4 {
if argts[0].IsVector() && argts[0].VectorElementCount() == 4 &&
argts[1].IsVector() && argts[1].VectorElementCount() == 4 &&
argts[2].IsVector() && argts[2].VectorElementCount() == 4 &&
argts[3].IsVector() && argts[3].VectorElementCount() == 4 {
return nil
}
case 16:

View File

@ -164,7 +164,7 @@ func Compile(p *shaderir.Program, version GLSLVersion) (vertexShader, fragmentSh
}
str := fmt.Sprintf("U%d[%d]", i, t.Length-1)
switch t.Sub[0].Main {
case shaderir.Vec2, shaderir.Vec3, shaderir.Vec4:
case shaderir.Vec2, shaderir.Vec3, shaderir.Vec4, shaderir.IVec2, shaderir.IVec3, shaderir.IVec4:
str += ".x"
case shaderir.Mat2, shaderir.Mat3, shaderir.Mat4:
str += "[0][0]"
@ -325,7 +325,9 @@ func (c *compileContext) varInit(p *shaderir.Program, t *shaderir.Type) string {
return "false"
case shaderir.Int:
return "0"
case shaderir.Float, shaderir.Vec2, shaderir.Vec3, shaderir.Vec4, shaderir.Mat2, shaderir.Mat3, shaderir.Mat4:
case shaderir.Float, shaderir.Vec2, shaderir.Vec3, shaderir.Vec4,
shaderir.IVec2, shaderir.IVec3, shaderir.IVec4,
shaderir.Mat2, shaderir.Mat3, shaderir.Mat4:
return fmt.Sprintf("%s(0)", basicTypeString(t.Main))
default:
t0, t1 := c.typ(p, t)

View File

@ -92,6 +92,12 @@ func basicTypeString(t shaderir.BasicType) string {
return "vec3"
case shaderir.Vec4:
return "vec4"
case shaderir.IVec2:
return "ivec2"
case shaderir.IVec3:
return "ivec3"
case shaderir.IVec4:
return "ivec4"
case shaderir.Mat2:
return "mat2"
case shaderir.Mat3:

View File

@ -215,7 +215,7 @@ func (c *compileContext) varInit(p *shaderir.Program, t *shaderir.Type) string {
panic("not implemented")
case shaderir.Bool:
return "false"
case shaderir.Int:
case shaderir.Int, shaderir.IVec2, shaderir.IVec3, shaderir.IVec4:
return "0"
case shaderir.Float, shaderir.Vec2, shaderir.Vec3, shaderir.Vec4, shaderir.Mat2, shaderir.Mat3, shaderir.Mat4:
return "0.0"
@ -404,7 +404,7 @@ func (c *compileContext) block(p *shaderir.Program, topBlock, block *shaderir.Bl
}
if callee.Type == shaderir.BuiltinFuncExpr {
switch callee.BuiltinFunc {
case shaderir.Vec2F, shaderir.Vec3F, shaderir.Vec4F:
case shaderir.Vec2F, shaderir.Vec3F, shaderir.Vec4F, shaderir.IVec2F, shaderir.IVec3F, shaderir.IVec4F:
if len(args) == 1 {
// Use casting. For example, `float4(1)` doesn't work.
return fmt.Sprintf("(%s)(%s)", expr(&e.Exprs[0]), args[0])

View File

@ -46,19 +46,19 @@ func calculateMemoryOffsets(uniforms []shaderir.Type) []int {
case shaderir.Int:
offsets = append(offsets, head)
head += 4
case shaderir.Vec2:
case shaderir.Vec2, shaderir.IVec2:
if head%boundaryInBytes >= 4*3 {
head = align(head)
}
offsets = append(offsets, head)
head += 4 * 2
case shaderir.Vec3:
case shaderir.Vec3, shaderir.IVec3:
if head%boundaryInBytes >= 4*2 {
head = align(head)
}
offsets = append(offsets, head)
head += 4 * 3
case shaderir.Vec4:
case shaderir.Vec4, shaderir.IVec4:
if head%boundaryInBytes >= 4*1 {
head = align(head)
}

View File

@ -92,6 +92,12 @@ func basicTypeString(t shaderir.BasicType) string {
return "float3"
case shaderir.Vec4:
return "float4"
case shaderir.IVec2:
return "int2"
case shaderir.IVec3:
return "int3"
case shaderir.IVec4:
return "int4"
case shaderir.Mat2:
return "float2x2"
case shaderir.Mat3:
@ -115,6 +121,12 @@ func (c *compileContext) builtinFuncString(f shaderir.BuiltinFunc) string {
return "float3"
case shaderir.Vec4F:
return "float4"
case shaderir.IVec2F:
return "int2"
case shaderir.IVec3F:
return "int3"
case shaderir.IVec4F:
return "int4"
case shaderir.Mat2F:
return "float2x2"
case shaderir.Mat3F:

View File

@ -203,7 +203,9 @@ func (c *compileContext) varInit(p *shaderir.Program, t *shaderir.Type) string {
return "false"
case shaderir.Int:
return "0"
case shaderir.Float, shaderir.Vec2, shaderir.Vec3, shaderir.Vec4, shaderir.Mat2, shaderir.Mat3, shaderir.Mat4:
case shaderir.Float, shaderir.Vec2, shaderir.Vec3, shaderir.Vec4,
shaderir.IVec2, shaderir.IVec3, shaderir.IVec4,
shaderir.Mat2, shaderir.Mat3, shaderir.Mat4:
return fmt.Sprintf("%s(0)", basicTypeString(t.Main))
default:
t := c.typ(p, t)

View File

@ -100,6 +100,12 @@ func basicTypeString(t shaderir.BasicType) string {
return "float3"
case shaderir.Vec4:
return "float4"
case shaderir.IVec2:
return "int2"
case shaderir.IVec3:
return "int3"
case shaderir.IVec4:
return "int4"
case shaderir.Mat2:
return "float2x2"
case shaderir.Mat3:
@ -129,6 +135,12 @@ func builtinFuncString(f shaderir.BuiltinFunc) string {
return "float3"
case shaderir.Vec4F:
return "float4"
case shaderir.IVec2F:
return "int2"
case shaderir.IVec3F:
return "int3"
case shaderir.IVec4F:
return "int4"
case shaderir.Mat2F:
return "float2x2"
case shaderir.Mat3F:

View File

@ -224,6 +224,9 @@ const (
Vec2F BuiltinFunc = "vec2"
Vec3F BuiltinFunc = "vec3"
Vec4F BuiltinFunc = "vec4"
IVec2F BuiltinFunc = "ivec2"
IVec3F BuiltinFunc = "ivec3"
IVec4F BuiltinFunc = "ivec4"
Mat2F BuiltinFunc = "mat2"
Mat3F BuiltinFunc = "mat3"
Mat4F BuiltinFunc = "mat4"
@ -281,6 +284,9 @@ func ParseBuiltinFunc(str string) (BuiltinFunc, bool) {
Vec2F,
Vec3F,
Vec4F,
IVec2F,
IVec3F,
IVec4F,
Mat2F,
Mat3F,
Mat4F,

View File

@ -59,6 +59,12 @@ func (t *Type) String() string {
return "vec3"
case Vec4:
return "vec4"
case IVec2:
return "ivec2"
case IVec3:
return "ivec3"
case IVec4:
return "ivec4"
case Mat2:
return "mat2"
case Mat3:
@ -93,6 +99,12 @@ func (t *Type) Uint32Count() int {
return 3
case Vec4:
return 4
case IVec2:
return 2
case IVec3:
return 3
case IVec4:
return 4
case Mat2:
return 4
case Mat3:
@ -108,12 +120,31 @@ func (t *Type) Uint32Count() int {
func (t *Type) IsVector() bool {
switch t.Main {
case Vec2, Vec3, Vec4:
case Vec2, Vec3, Vec4, IVec2, IVec3, IVec4:
return true
}
return false
}
func (t *Type) VectorElementCount() int {
switch t.Main {
case Vec2:
return 2
case Vec3:
return 3
case Vec4:
return 4
case IVec2:
return 2
case IVec3:
return 3
case IVec4:
return 4
default:
return -1
}
}
func (t *Type) IsMatrix() bool {
switch t.Main {
case Mat2, Mat3, Mat4:
@ -132,6 +163,9 @@ const (
Vec2
Vec3
Vec4
IVec2
IVec3
IVec4
Mat2
Mat3
Mat4

View File

@ -1293,6 +1293,16 @@ var U [4]int
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
return vec4(float(U[0])/255.0, float(U[1])/255.0, float(U[2])/255.0, float(U[3])/255.0)
}
`
const intVec = `package main
var U0 ivec4
var U1 [2]ivec3
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
return vec4(float(U0.x)/255.0, float(U0.y)/255.0, float(U1[0].z)/255.0, float(U1[1].x)/255.0)
}
`
testCases := []struct {
@ -1382,6 +1392,57 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
Shader: intArray,
Want: color.RGBA{0x85, 0xa3, 0x08, 0xd3},
},
{
Name: "0xff,array",
Uniforms: map[string]any{
"U": [...]int{0xff, 0xff, 0xff, 0xff},
},
Shader: intArray,
Want: color.RGBA{0xff, 0xff, 0xff, 0xff},
},
{
Name: "int,array",
Uniforms: map[string]any{
"U": [...]int16{0x24, 0x3f, 0x6a, 0x88},
},
Shader: intArray,
Want: color.RGBA{0x24, 0x3f, 0x6a, 0x88},
},
{
Name: "uint,array",
Uniforms: map[string]any{
"U": [...]uint8{0x85, 0xa3, 0x08, 0xd3},
},
Shader: intArray,
Want: color.RGBA{0x85, 0xa3, 0x08, 0xd3},
},
{
Name: "0xff,ivec",
Uniforms: map[string]any{
"U0": [...]int{0xff, 0xff, 0xff, 0xff},
"U1": [...]int{0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
},
Shader: intVec,
Want: color.RGBA{0xff, 0xff, 0xff, 0xff},
},
{
Name: "int,ivec",
Uniforms: map[string]any{
"U0": [...]int16{0x24, 0x3f, 0x6a, 0x88},
"U1": [...]int16{0x85, 0xa3, 0x08, 0xd3, 0x13, 0x19},
},
Shader: intVec,
Want: color.RGBA{0x24, 0x3f, 0x08, 0xd3},
},
{
Name: "uint,ivec",
Uniforms: map[string]any{
"U0": [...]uint8{0x24, 0x3f, 0x6a, 0x88},
"U1": [...]uint8{0x85, 0xa3, 0x08, 0xd3, 0x13, 0x19},
},
Shader: intVec,
Want: color.RGBA{0x24, 0x3f, 0x08, 0xd3},
},
}
for _, tc := range testCases {
tc := tc
@ -1408,7 +1469,7 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
}
// Issue #2463
func TestShaderVec3Array(t *testing.T) {
func TestShaderUniformVec3Array(t *testing.T) {
const shader = `package main
var U [4]vec3