mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-05 01:15:35 +00:00
gpu: setup OpenGL ES texture uniforms automatically from shader metadata
Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
+6
-4
@@ -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
@@ -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
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user