shader: Use arrays at uniform variables

Fixes #1274
This commit is contained in:
Hajime Hoshi 2020-08-01 16:20:49 +09:00
parent 2b4cf7fd17
commit a4334c5464
8 changed files with 87 additions and 59 deletions

View File

@ -23,19 +23,14 @@ const (
// PreservedUniformVariablesNum represents the number of preserved uniform variables.
// Any shaders in Ebiten must have these uniform variables.
//
// All the preversed uniform variables are vec2 so far.
PreservedUniformVariablesNum = 1 + // the destination texture size
ShaderImageNum + // the texture sizes
(ShaderImageNum - 1) // the offsets of the second and the following images
)
1 + // the texture sizes array
1 // the offsets array of the second and the following images
func TextureOffsetUniformVariableIndex(i int) int {
if i == 0 {
panic("graphics: the texture 0 doesn't have its offset")
}
return 1 + ShaderImageNum + i - 1
}
DestinationTextureSizeUniformVariableIndex = 0
TextureSizesUniformVariableIndex = 1
TextureOffsetsUniformVariableIndex = 2
)
const (
IndicesNum = (1 << 16) / 3 * 3 // Adjust num for triangles.

View File

@ -311,24 +311,32 @@ func (g *Graphics) DrawShader(dst driver.ImageID, srcs [graphics.ShaderImageNum]
us[0].value = []float32{float32(vw), float32(vh)}
us[0].typ = s.ir.Uniforms[0]
vsizes := make([]float32, 2*len(srcs))
for i, src := range srcs {
img := g.images[src]
var w, h int
if img != nil {
w, h = img.framebufferSize()
if img := g.images[src]; img != nil {
w, h := img.framebufferSize()
vsizes[2*i] = float32(w)
vsizes[2*i+1] = float32(h)
}
const offset = 1
us[i+offset].name = fmt.Sprintf("U%d", i+offset)
us[i+offset].value = []float32{float32(w), float32(h)}
us[i+offset].typ = s.ir.Uniforms[i+offset]
}
{
const idx = 1
us[idx].name = fmt.Sprintf("U%d", idx)
us[idx].value = vsizes
us[idx].typ = s.ir.Uniforms[idx]
}
voffsets := make([]float32, 2*len(offsets))
for i, o := range offsets {
const offset = 1 + graphics.ShaderImageNum
o := o
us[i+offset].name = fmt.Sprintf("U%d", i+offset)
us[i+offset].value = o[:]
us[i+offset].typ = s.ir.Uniforms[i+offset]
voffsets[2*i] = o[0]
voffsets[2*i+1] = o[1]
}
{
const idx = 1 + 1
us[idx].name = fmt.Sprintf("U%d", idx)
us[idx].value = voffsets
us[idx].typ = s.ir.Uniforms[idx]
}
for i, v := range uniforms {

View File

@ -182,11 +182,6 @@ func (cs *compileState) parse(f *ast.File) {
}
}
// TODO: Check len(unames) == graphics.PreservedUniformVariablesNum. Unfortunately this is not true on tests.
for _, t := range utypes {
if got, want := t.Main, shaderir.Vec2; got != want {
panic(fmt.Sprintf("shader: all the preserved uniform variables' types must be %v but %v", want, got))
}
}
for i, u := range cs.uniforms {
if !strings.HasPrefix(u, "__") {
unames = append(unames, u)

View File

@ -1,17 +1,17 @@
uniform vec2[4] U0;
uniform vec2 U0[4];
void F0(out vec2[2] l0);
void F1(out vec2[2] l0);
void F0(out vec2 l0[2]);
void F1(out vec2 l0[2]);
void F0(out vec2[2] l0) {
vec2[2] l1 = vec2[2](vec2(0), vec2(0));
void F0(out vec2 l0[2]) {
vec2 l1[2] = vec2[2](vec2(0), vec2(0));
l0 = l1;
return;
}
void F1(out vec2[2] l0) {
vec2[2] l1 = vec2[2](vec2(0), vec2(0));
vec2[2] l2 = vec2[2](vec2(0), vec2(0));
void F1(out vec2 l0[2]) {
vec2 l1[2] = vec2[2](vec2(0), vec2(0));
vec2 l2[2] = vec2[2](vec2(0), vec2(0));
(l1)[0] = vec2(1.0);
l2 = l1;
((l2)[1]).y = vec2(2.0);

View File

@ -168,12 +168,12 @@ func (p *Program) Glsl() (vertexShader, fragmentShader string) {
return strings.Join(vslines, "\n") + "\n", strings.Join(fslines, "\n") + "\n"
}
func (p *Program) glslType(t *Type) string {
func (p *Program) glslType(t *Type) (string, string) {
switch t.Main {
case None:
return "void"
return "void", ""
case Struct:
return p.structName(t)
return p.structName(t), ""
default:
return t.Glsl()
}
@ -186,7 +186,8 @@ func (p *Program) glslVarDecl(t *Type, varname string) string {
case Struct:
return fmt.Sprintf("%s %s", p.structName(t), varname)
default:
return fmt.Sprintf("%s %s", t.Glsl(), varname)
t0, t1 := t.Glsl()
return fmt.Sprintf("%s %s%s", t0, varname, t1)
}
}
@ -200,7 +201,8 @@ func (p *Program) glslVarInit(t *Type) string {
for i := 0; i < t.Length; i++ {
es = append(es, init)
}
return fmt.Sprintf("%s[%d](%s)", t.Sub[0].Glsl(), t.Length, strings.Join(es, ", "))
t0, t1 := t.Glsl()
return fmt.Sprintf("%s%s(%s)", t0, t1, strings.Join(es, ", "))
case Struct:
panic("not implemented")
case Bool:
@ -222,7 +224,8 @@ func (p *Program) glslVarInit(t *Type) string {
case Mat4:
return "mat4(0)"
default:
panic(fmt.Sprintf("?(unexpected type: %s)", p.glslType(t)))
t0, t1 := p.glslType(t)
panic(fmt.Sprintf("?(unexpected type: %s%s)", t0, t1))
}
}
@ -242,7 +245,8 @@ func (p *Program) glslFunc(f *Func, prototype bool) []string {
argsstr = strings.Join(args, ", ")
}
sig := fmt.Sprintf("%s F%d(%s)", p.glslType(&f.Return), f.Index, argsstr)
t0, t1 := p.glslType(&f.Return)
sig := fmt.Sprintf("%s%s F%d(%s)", t0, t1, f.Index, argsstr)
var lines []string
if prototype {
@ -436,7 +440,8 @@ func (p *Program) glslBlock(topBlock, block *Block, level int, localVarIndex int
t := s.ForVarType
init := constantToNumberLiteral(ct, s.ForInit)
end := constantToNumberLiteral(ct, s.ForEnd)
lines = append(lines, fmt.Sprintf("%sfor (%s %s = %s; %s %s %s; %s) {", idt, t.Glsl(), v, init, v, op, end, delta))
t0, t1 := t.Glsl()
lines = append(lines, fmt.Sprintf("%sfor (%s %s%s = %s; %s %s %s; %s) {", idt, t0, v, t1, init, v, op, end, delta))
lines = append(lines, p.glslBlock(topBlock, &s.Blocks[0], level+1, localVarIndex)...)
lines = append(lines, fmt.Sprintf("%s}", idt))
case Continue:

View File

@ -85,14 +85,15 @@ func (t *Type) serialize() string {
return t.String()
}
func (t *Type) Glsl() string {
func (t *Type) Glsl() (string, string) {
switch t.Main {
case Array:
return fmt.Sprintf("%s[%d]", t.Sub[0].Glsl(), t.Length)
t0, t1 := t.Sub[0].Glsl()
return t0 + t1, fmt.Sprintf("[%d]", t.Length)
case Struct:
panic("shaderir: a struct is not implemented")
default:
return t.Main.glsl()
return t.Main.glsl(), ""
}
}

View File

@ -225,8 +225,19 @@ func defaultProgram() shaderir.Program {
}
p.Uniforms = make([]shaderir.Type, graphics.PreservedUniformVariablesNum)
for i := range p.Uniforms {
p.Uniforms[i] = shaderir.Type{Main: shaderir.Vec2}
// Destination texture size
p.Uniforms[0] = shaderir.Type{Main: shaderir.Vec2}
// Source texture sizes
p.Uniforms[1] = shaderir.Type{
Main: shaderir.Array,
Length: graphics.ShaderImageNum,
Sub: []shaderir.Type{{Main: shaderir.Vec2}},
}
// Source texture offsets
p.Uniforms[2] = shaderir.Type{
Main: shaderir.Array,
Length: graphics.ShaderImageNum - 1,
Sub: []shaderir.Type{{Main: shaderir.Vec2}},
}
return p
}
@ -350,8 +361,18 @@ func ShaderProgramImages(imageNum int) shaderir.Program {
Exprs: []shaderir.Expr{
texPos,
{
Type: shaderir.UniformVariable,
Index: graphics.TextureOffsetUniformVariableIndex(i),
Type: shaderir.Index,
Exprs: []shaderir.Expr{
{
Type: shaderir.UniformVariable,
Index: graphics.TextureOffsetsUniformVariableIndex,
},
{
Type: shaderir.NumberExpr,
Const: constant.MakeInt64(int64(i - 1)),
ConstType: shaderir.ConstTypeInt,
},
},
},
},
}

View File

@ -36,23 +36,26 @@ func textureDstSize() vec2 {
}
`
shaderSuffix += fmt.Sprintf(`
var __textureSizes [%d]vec2
`, graphics.ShaderImageNum)
for i := 0; i < graphics.ShaderImageNum; i++ {
shaderSuffix += fmt.Sprintf(`
var __textureSize%[1]d vec2
func texture%[1]dSize() vec2 {
return __textureSize%[1]d
return __textureSizes[%[1]d]
}
`, i)
}
shaderSuffix += fmt.Sprintf(`
var __textureOffsets [%d]vec2
`, graphics.ShaderImageNum-1)
for i := 0; i < graphics.ShaderImageNum; i++ {
var offset string
if i >= 1 {
shaderSuffix += fmt.Sprintf(`
var __textureOffset%[1]d vec2
`, i)
offset = fmt.Sprintf(" + __textureOffset%d", i)
offset = fmt.Sprintf(" + __textureOffsets[%d]", i-1)
}
// __t%d is a special variable for a texture variable.
shaderSuffix += fmt.Sprintf(`