gpu: setup OpenGL ES texture uniforms automatically from shader metadata

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2020-02-20 21:39:29 +01:00
parent 5c359bbf89
commit 4e3bfd5b1b
6 changed files with 77 additions and 30 deletions
+6 -4
View File
@@ -46,6 +46,12 @@ type ShaderSources struct {
Uniforms []UniformLocation Uniforms []UniformLocation
UniformSize int UniformSize int
Inputs []InputLocation Inputs []InputLocation
Textures []TextureBinding
}
type TextureBinding struct {
Name string
Binding int
} }
type UniformLocation struct { type UniformLocation struct {
@@ -109,12 +115,8 @@ type Program interface {
Release() Release()
SetVertexUniforms(buf Buffer) SetVertexUniforms(buf Buffer)
SetFragmentUniforms(buf Buffer) SetFragmentUniforms(buf Buffer)
UniformFor(uniform string) Uniform
Uniform1i(u Uniform, v int)
} }
type Uniform interface{}
type Buffer interface { type Buffer interface {
BindVertex(stride, offset int) BindVertex(stride, offset int)
BindIndex() BindIndex()
+43 -6
View File
@@ -27,6 +27,12 @@ type shaderArgs struct {
Header string Header string
} }
// TextureBinding matches gpu.TextureBinding.
type TextureBinding struct {
Name string
Binding int
}
// InputLocation matches gpu.InputLocation. // InputLocation matches gpu.InputLocation.
type InputLocation struct { type InputLocation struct {
Name string Name string
@@ -90,6 +96,7 @@ func generate() error {
hlsl []byte hlsl []byte
inputs []InputLocation inputs []InputLocation
uniforms []UniformLocation uniforms []UniformLocation
textures []TextureBinding
uniformSize int uniformSize int
} }
args := [nvariants]shaderArgs{ args := [nvariants]shaderArgs{
@@ -109,7 +116,7 @@ func generate() error {
} }
// Make the GL ES 2 source compatible with desktop GL 3. // Make the GL ES 2 source compatible with desktop GL 3.
gles2 = "#version 100\n" + gles2 gles2 = "#version 100\n" + gles2
inputs, uniforms, uniformSize, err := parseReflection(reflect) inputs, uniforms, textures, uniformSize, err := parseReflection(reflect)
if err != nil { if err != nil {
return err return err
} }
@@ -138,6 +145,7 @@ func generate() error {
variants[i].hlsl = hlslc variants[i].hlsl = hlslc
variants[i].inputs = inputs variants[i].inputs = inputs
variants[i].uniforms = uniforms variants[i].uniforms = uniforms
variants[i].textures = textures
variants[i].uniformSize = uniformSize variants[i].uniformSize = uniformSize
} }
name := filepath.Base(shader) name := filepath.Base(shader)
@@ -165,8 +173,17 @@ func generate() error {
fmt.Fprintf(&out, "{Name: %q, Type: %d, Size: %d, Offset: %d},\n", u.Name, u.Type, u.Size, u.Offset) fmt.Fprintf(&out, "{Name: %q, Type: %d, Size: %d, Offset: %d},\n", u.Name, u.Type, u.Size, u.Offset)
} }
fmt.Fprintf(&out, "},\n") fmt.Fprintf(&out, "},\n")
}
if src.uniformSize != 0 {
fmt.Fprintf(&out, "UniformSize: %d,\n", src.uniformSize) fmt.Fprintf(&out, "UniformSize: %d,\n", src.uniformSize)
} }
if len(src.textures) > 0 {
fmt.Fprintf(&out, "Textures: []TextureBinding{\n")
for _, t := range src.textures {
fmt.Fprintf(&out, "{Name: %q, Binding: %d},\n", t.Name, t.Binding)
}
fmt.Fprintf(&out, "},\n")
}
fmt.Fprintf(&out, "GLES2: %#v,\n", src.gles2) fmt.Fprintf(&out, "GLES2: %#v,\n", src.gles2)
fmt.Fprintf(&out, "/*\n%s\n*/\n", src.hlslSrc) fmt.Fprintf(&out, "/*\n%s\n*/\n", src.hlslSrc)
fmt.Fprintf(&out, "HLSL: %#v,\n", src.hlsl) fmt.Fprintf(&out, "HLSL: %#v,\n", src.hlsl)
@@ -191,7 +208,7 @@ func generate() error {
return ioutil.WriteFile("shaders.go", gosrc, 0644) return ioutil.WriteFile("shaders.go", gosrc, 0644)
} }
func parseReflection(jsonData []byte) ([]InputLocation, []UniformLocation, int, error) { func parseReflection(jsonData []byte) ([]InputLocation, []UniformLocation, []TextureBinding, int, error) {
type InputReflection struct { type InputReflection struct {
ID int `json:"id"` ID int `json:"id"`
Name string `json:"name"` Name string `json:"name"`
@@ -214,9 +231,18 @@ func parseReflection(jsonData []byte) ([]InputLocation, []UniformLocation, int,
Size int `json:"block_size"` Size int `json:"block_size"`
Members []UniformMemberReflection `json:"members"` Members []UniformMemberReflection `json:"members"`
} }
type TextureReflection struct {
ID int `json:"id"`
Name string `json:"name"`
Set int `json:"set"`
Binding int `json:"binding"`
Dimension string `json:"dimension"`
Format string `json:"format"`
}
type shaderReflection struct { type shaderReflection struct {
Inputs []InputReflection `json:"inputs"` Inputs []InputReflection `json:"inputs"`
UniformBuffers []UniformBufferReflection `json:"uniform_buffers"` UniformBuffers []UniformBufferReflection `json:"uniform_buffers"`
Textures []TextureReflection `json:"textures"`
} }
type shaderMetadata struct { type shaderMetadata struct {
VS shaderReflection `json:"vs"` VS shaderReflection `json:"vs"`
@@ -224,14 +250,14 @@ func parseReflection(jsonData []byte) ([]InputLocation, []UniformLocation, int,
} }
var reflect shaderMetadata var reflect shaderMetadata
if err := json.Unmarshal(jsonData, &reflect); err != nil { if err := json.Unmarshal(jsonData, &reflect); err != nil {
return nil, nil, 0, fmt.Errorf("parseReflection: %v", err) return nil, nil, nil, 0, fmt.Errorf("parseReflection: %v", err)
} }
var inputs []InputLocation var inputs []InputLocation
inputRef := reflect.VS.Inputs inputRef := reflect.VS.Inputs
for _, input := range inputRef { for _, input := range inputRef {
dataType, dataSize, err := parseDataType(input.Type) dataType, dataSize, err := parseDataType(input.Type)
if err != nil { if err != nil {
return nil, nil, 0, fmt.Errorf("parseReflection: %v", err) return nil, nil, nil, 0, fmt.Errorf("parseReflection: %v", err)
} }
inputs = append(inputs, InputLocation{ inputs = append(inputs, InputLocation{
Name: input.Name, Name: input.Name,
@@ -255,7 +281,7 @@ func parseReflection(jsonData []byte) ([]InputLocation, []UniformLocation, int,
for _, member := range block.Members { for _, member := range block.Members {
dataType, size, err := parseDataType(member.Type) dataType, size, err := parseDataType(member.Type)
if err != nil { if err != nil {
return nil, nil, 0, fmt.Errorf("parseReflection: %v", err) return nil, nil, nil, 0, fmt.Errorf("parseReflection: %v", err)
} }
ublocks = append(ublocks, UniformLocation{ ublocks = append(ublocks, UniformLocation{
// Synthetic name generated by glslcc. // Synthetic name generated by glslcc.
@@ -267,7 +293,18 @@ func parseReflection(jsonData []byte) ([]InputLocation, []UniformLocation, int,
} }
blockOffset += block.Size blockOffset += block.Size
} }
return inputs, ublocks, blockOffset, nil textures := reflect.VS.Textures
if len(textures) == 0 {
textures = reflect.FS.Textures
}
var texBinds []TextureBinding
for _, texture := range textures {
texBinds = append(texBinds, TextureBinding{
Name: texture.Name,
Binding: texture.Binding,
})
}
return inputs, ublocks, texBinds, blockOffset, nil
} }
func parseDataType(t string) (DataType, int, error) { func parseDataType(t string) (DataType, int, error) {
+14 -10
View File
@@ -366,6 +366,20 @@ func (b *Backend) NewProgram(vssrc, fssrc gpu.ShaderSources) (gpu.Program, error
obj: p, obj: p,
nattr: len(attr), nattr: len(attr),
} }
gpuProg.Bind()
// Bind texture uniforms.
for _, tex := range vssrc.Textures {
u := b.funcs.GetUniformLocation(p, tex.Name)
if u.valid() {
b.funcs.Uniform1i(u, tex.Binding)
}
}
for _, tex := range fssrc.Textures {
u := b.funcs.GetUniformLocation(p, tex.Name)
if u.valid() {
b.funcs.Uniform1i(u, tex.Binding)
}
}
gpuProg.vertUniforms.setup(b.funcs, p, vssrc.UniformSize, vssrc.Uniforms) gpuProg.vertUniforms.setup(b.funcs, p, vssrc.UniformSize, vssrc.Uniforms)
gpuProg.fragUniforms.setup(b.funcs, p, fssrc.UniformSize, fssrc.Uniforms) gpuProg.fragUniforms.setup(b.funcs, p, fssrc.UniformSize, fssrc.Uniforms)
return gpuProg, nil return gpuProg, nil
@@ -389,21 +403,11 @@ func (p *gpuProgram) updateUniforms() {
p.fragUniforms.update(p.backend.funcs) p.fragUniforms.update(p.backend.funcs)
} }
func (p *gpuProgram) Uniform1i(u gpu.Uniform, v int) {
p.Bind()
p.backend.funcs.Uniform1i(u.(Uniform), v)
}
func (p *gpuProgram) Bind() { func (p *gpuProgram) Bind() {
p.backend.useProgram(p) p.backend.useProgram(p)
p.backend.enableVertexArrays(p.nattr) p.backend.enableVertexArrays(p.nattr)
} }
func (p *gpuProgram) UniformFor(uniform string) gpu.Uniform {
f := p.backend.funcs
return GetUniformLocation(f, p.obj, uniform)
}
func (p *gpuProgram) Release() { func (p *gpuProgram) Release() {
p.backend.funcs.DeleteProgram(p.obj) p.backend.funcs.DeleteProgram(p.obj)
} }
-2
View File
@@ -425,8 +425,6 @@ func newBlitter(ctx Backend) *blitter {
} }
b.prog = prog b.prog = prog
b.layout = layout b.layout = layout
texProg := b.prog[materialTexture].prog
texProg.Uniform1i(texProg.UniformFor("tex"), 0)
return b return b
} }
-7
View File
@@ -134,11 +134,6 @@ func newCoverer(ctx Backend) *coverer {
} }
c.prog = prog c.prog = prog
c.layout = layout c.layout = layout
texProg := prog[materialTexture].prog
texProg.Uniform1i(texProg.UniformFor("tex"), 0)
for _, p := range prog {
p.prog.Uniform1i(p.prog.UniformFor("cover"), 1)
}
return c return c
} }
@@ -190,8 +185,6 @@ func newStenciler(ctx Backend) *stenciler {
panic(err) panic(err)
} }
vertUniforms = newUniformBuffer(ctx, &st.iprog.uniforms.vert) vertUniforms = newUniformBuffer(ctx, &st.iprog.uniforms.vert)
coverLoc := iprog.UniformFor("cover")
iprog.Uniform1i(coverLoc, 0)
st.iprog.prog = newProgram(iprog, vertUniforms, nil) st.iprog.prog = newProgram(iprog, vertUniforms, nil)
st.iprog.layout = iprogLayout st.iprog.layout = iprogLayout
return st return st
+14 -1
View File
@@ -48,6 +48,9 @@ var (
HLSL: []byte(nil), HLSL: []byte(nil),
}, },
ShaderSources{ ShaderSources{
Textures: []TextureBinding{
{Name: "tex", Binding: 0},
},
GLES2: "#version 100\nprecision mediump float;\nprecision highp int;\n\nuniform mediump sampler2D tex;\n\nvarying vec2 vUV;\n\nvoid main()\n{\n gl_FragData[0] = texture2D(tex, vUV);\n}\n\n", GLES2: "#version 100\nprecision mediump float;\nprecision highp int;\n\nuniform mediump sampler2D tex;\n\nvarying vec2 vUV;\n\nvoid main()\n{\n gl_FragData[0] = texture2D(tex, vUV);\n}\n\n",
/* /*
Texture2D<float4> tex : register(t0); Texture2D<float4> tex : register(t0);
@@ -155,7 +158,10 @@ var (
{Name: "_12._color", Type: 0, Size: 4, Offset: 0}, {Name: "_12._color", Type: 0, Size: 4, Offset: 0},
}, },
UniformSize: 16, UniformSize: 16,
GLES2: "#version 100\nprecision mediump float;\nprecision highp int;\n\nstruct Color\n{\n vec4 _color;\n};\n\nuniform Color _12;\n\nuniform mediump sampler2D cover;\n\nvarying highp vec2 vCoverUV;\nvarying vec2 vUV;\n\nvoid main()\n{\n gl_FragData[0] = _12._color;\n float cover_1 = abs(texture2D(cover, vCoverUV).x);\n gl_FragData[0] *= cover_1;\n}\n\n", Textures: []TextureBinding{
{Name: "cover", Binding: 1},
},
GLES2: "#version 100\nprecision mediump float;\nprecision highp int;\n\nstruct Color\n{\n vec4 _color;\n};\n\nuniform Color _12;\n\nuniform mediump sampler2D cover;\n\nvarying highp vec2 vCoverUV;\nvarying vec2 vUV;\n\nvoid main()\n{\n gl_FragData[0] = _12._color;\n float cover_1 = abs(texture2D(cover, vCoverUV).x);\n gl_FragData[0] *= cover_1;\n}\n\n",
/* /*
cbuffer Color : register(b0) cbuffer Color : register(b0)
{ {
@@ -201,6 +207,10 @@ var (
HLSL: []byte(nil), HLSL: []byte(nil),
}, },
ShaderSources{ ShaderSources{
Textures: []TextureBinding{
{Name: "tex", Binding: 0},
{Name: "cover", Binding: 1},
},
GLES2: "#version 100\nprecision mediump float;\nprecision highp int;\n\nuniform mediump sampler2D tex;\nuniform mediump sampler2D cover;\n\nvarying vec2 vUV;\nvarying highp vec2 vCoverUV;\n\nvoid main()\n{\n gl_FragData[0] = texture2D(tex, vUV);\n float cover_1 = abs(texture2D(cover, vCoverUV).x);\n gl_FragData[0] *= cover_1;\n}\n\n", GLES2: "#version 100\nprecision mediump float;\nprecision highp int;\n\nuniform mediump sampler2D tex;\nuniform mediump sampler2D cover;\n\nvarying vec2 vUV;\nvarying highp vec2 vCoverUV;\n\nvoid main()\n{\n gl_FragData[0] = texture2D(tex, vUV);\n float cover_1 = abs(texture2D(cover, vCoverUV).x);\n gl_FragData[0] *= cover_1;\n}\n\n",
/* /*
Texture2D<float4> tex : register(t0); Texture2D<float4> tex : register(t0);
@@ -315,6 +325,9 @@ var (
HLSL: []byte(nil), HLSL: []byte(nil),
} }
shader_intersect_frag = ShaderSources{ shader_intersect_frag = ShaderSources{
Textures: []TextureBinding{
{Name: "cover", Binding: 0},
},
GLES2: "#version 100\nprecision mediump float;\nprecision highp int;\n\nuniform mediump sampler2D cover;\n\nvarying highp vec2 vUV;\n\nvoid main()\n{\n float cover_1 = abs(texture2D(cover, vUV).x);\n gl_FragData[0].x = cover_1;\n}\n\n", GLES2: "#version 100\nprecision mediump float;\nprecision highp int;\n\nuniform mediump sampler2D cover;\n\nvarying highp vec2 vUV;\n\nvoid main()\n{\n float cover_1 = abs(texture2D(cover, vUV).x);\n gl_FragData[0].x = cover_1;\n}\n\n",
/* /*
Texture2D<float4> cover : register(t0); Texture2D<float4> cover : register(t0);