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
UniformSize int
Inputs []InputLocation
Textures []TextureBinding
}
type TextureBinding struct {
Name string
Binding int
}
type UniformLocation struct {
@@ -109,12 +115,8 @@ type Program interface {
Release()
SetVertexUniforms(buf Buffer)
SetFragmentUniforms(buf Buffer)
UniformFor(uniform string) Uniform
Uniform1i(u Uniform, v int)
}
type Uniform interface{}
type Buffer interface {
BindVertex(stride, offset int)
BindIndex()
+43 -6
View File
@@ -27,6 +27,12 @@ type shaderArgs struct {
Header string
}
// TextureBinding matches gpu.TextureBinding.
type TextureBinding struct {
Name string
Binding int
}
// InputLocation matches gpu.InputLocation.
type InputLocation struct {
Name string
@@ -90,6 +96,7 @@ func generate() error {
hlsl []byte
inputs []InputLocation
uniforms []UniformLocation
textures []TextureBinding
uniformSize int
}
args := [nvariants]shaderArgs{
@@ -109,7 +116,7 @@ func generate() error {
}
// Make the GL ES 2 source compatible with desktop GL 3.
gles2 = "#version 100\n" + gles2
inputs, uniforms, uniformSize, err := parseReflection(reflect)
inputs, uniforms, textures, uniformSize, err := parseReflection(reflect)
if err != nil {
return err
}
@@ -138,6 +145,7 @@ func generate() error {
variants[i].hlsl = hlslc
variants[i].inputs = inputs
variants[i].uniforms = uniforms
variants[i].textures = textures
variants[i].uniformSize = uniformSize
}
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, "},\n")
}
if src.uniformSize != 0 {
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, "/*\n%s\n*/\n", src.hlslSrc)
fmt.Fprintf(&out, "HLSL: %#v,\n", src.hlsl)
@@ -191,7 +208,7 @@ func generate() error {
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 {
ID int `json:"id"`
Name string `json:"name"`
@@ -214,9 +231,18 @@ func parseReflection(jsonData []byte) ([]InputLocation, []UniformLocation, int,
Size int `json:"block_size"`
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 {
Inputs []InputReflection `json:"inputs"`
UniformBuffers []UniformBufferReflection `json:"uniform_buffers"`
Textures []TextureReflection `json:"textures"`
}
type shaderMetadata struct {
VS shaderReflection `json:"vs"`
@@ -224,14 +250,14 @@ func parseReflection(jsonData []byte) ([]InputLocation, []UniformLocation, int,
}
var reflect shaderMetadata
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
inputRef := reflect.VS.Inputs
for _, input := range inputRef {
dataType, dataSize, err := parseDataType(input.Type)
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{
Name: input.Name,
@@ -255,7 +281,7 @@ func parseReflection(jsonData []byte) ([]InputLocation, []UniformLocation, int,
for _, member := range block.Members {
dataType, size, err := parseDataType(member.Type)
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{
// Synthetic name generated by glslcc.
@@ -267,7 +293,18 @@ func parseReflection(jsonData []byte) ([]InputLocation, []UniformLocation, int,
}
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) {
+14 -10
View File
@@ -366,6 +366,20 @@ func (b *Backend) NewProgram(vssrc, fssrc gpu.ShaderSources) (gpu.Program, error
obj: p,
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.fragUniforms.setup(b.funcs, p, fssrc.UniformSize, fssrc.Uniforms)
return gpuProg, nil
@@ -389,21 +403,11 @@ func (p *gpuProgram) updateUniforms() {
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() {
p.backend.useProgram(p)
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() {
p.backend.funcs.DeleteProgram(p.obj)
}
-2
View File
@@ -425,8 +425,6 @@ func newBlitter(ctx Backend) *blitter {
}
b.prog = prog
b.layout = layout
texProg := b.prog[materialTexture].prog
texProg.Uniform1i(texProg.UniformFor("tex"), 0)
return b
}
-7
View File
@@ -134,11 +134,6 @@ func newCoverer(ctx Backend) *coverer {
}
c.prog = prog
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
}
@@ -190,8 +185,6 @@ func newStenciler(ctx Backend) *stenciler {
panic(err)
}
vertUniforms = newUniformBuffer(ctx, &st.iprog.uniforms.vert)
coverLoc := iprog.UniformFor("cover")
iprog.Uniform1i(coverLoc, 0)
st.iprog.prog = newProgram(iprog, vertUniforms, nil)
st.iprog.layout = iprogLayout
return st
+14 -1
View File
@@ -48,6 +48,9 @@ var (
HLSL: []byte(nil),
},
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",
/*
Texture2D<float4> tex : register(t0);
@@ -155,7 +158,10 @@ var (
{Name: "_12._color", Type: 0, Size: 4, Offset: 0},
},
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)
{
@@ -201,6 +207,10 @@ var (
HLSL: []byte(nil),
},
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",
/*
Texture2D<float4> tex : register(t0);
@@ -315,6 +325,9 @@ var (
HLSL: []byte(nil),
}
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",
/*
Texture2D<float4> cover : register(t0);