diff --git a/gpu/backend.go b/gpu/backend.go index 2c411090..9e56f040 100644 --- a/gpu/backend.go +++ b/gpu/backend.go @@ -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() diff --git a/gpu/build.go b/gpu/build.go index 347e4360..c0647cdb 100644 --- a/gpu/build.go +++ b/gpu/build.go @@ -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) { diff --git a/gpu/gl/backend.go b/gpu/gl/backend.go index ed11dadd..381050e6 100644 --- a/gpu/gl/backend.go +++ b/gpu/gl/backend.go @@ -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) } diff --git a/gpu/gpu.go b/gpu/gpu.go index ee188a64..a19079f1 100644 --- a/gpu/gpu.go +++ b/gpu/gpu.go @@ -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 } diff --git a/gpu/path.go b/gpu/path.go index 3fd7f25a..5d4fef02 100644 --- a/gpu/path.go +++ b/gpu/path.go @@ -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 diff --git a/gpu/shaders.go b/gpu/shaders.go index 642369ea..e6053082 100644 --- a/gpu/shaders.go +++ b/gpu/shaders.go @@ -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 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 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 cover : register(t0);