gpu,gpu/gl: implement shader uniform buffers

Emulate them for the OpenGL ES backend because 2.0 doesn't support uniform
buffers. The future d3d backend only supports uniform (constant) buffers.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2020-02-19 21:06:30 +01:00
parent ef3e94e7a7
commit 646a767665
12 changed files with 504 additions and 252 deletions
+19 -14
View File
@@ -85,16 +85,17 @@ func generate() error {
for _, shader := range shaders {
const nvariants = 2
var variants [nvariants]struct {
gles2 string
hlslSrc string
hlsl []byte
inputs []InputLocation
uniforms []UniformLocation
gles2 string
hlslSrc string
hlsl []byte
inputs []InputLocation
uniforms []UniformLocation
uniformSize int
}
args := [nvariants]shaderArgs{
{
FetchColorExpr: `color.color`,
Header: `layout(binding=0) uniform Color { vec4 color; } color;`,
FetchColorExpr: `_color`,
Header: `layout(binding=0) uniform Color { vec4 _color; };`,
},
{
FetchColorExpr: `texture(tex, vUV)`,
@@ -108,7 +109,7 @@ func generate() error {
}
// Make the GL ES 2 source compatible with desktop GL 3.
gles2 = "#version 100\n" + gles2
inputs, uniforms, err := parseReflection(reflect)
inputs, uniforms, uniformSize, err := parseReflection(reflect)
if err != nil {
return err
}
@@ -137,6 +138,7 @@ func generate() error {
variants[i].hlsl = hlslc
variants[i].inputs = inputs
variants[i].uniforms = uniforms
variants[i].uniformSize = uniformSize
}
name := filepath.Base(shader)
name = strings.ReplaceAll(name, ".", "_")
@@ -163,6 +165,7 @@ 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")
fmt.Fprintf(&out, "UniformSize: %d,\n", src.uniformSize)
}
fmt.Fprintf(&out, "GLES2: %#v,\n", src.gles2)
fmt.Fprintf(&out, "/*\n%s\n*/\n", src.hlslSrc)
@@ -188,7 +191,7 @@ func generate() error {
return ioutil.WriteFile("shaders.go", gosrc, 0644)
}
func parseReflection(jsonData []byte) ([]InputLocation, []UniformLocation, error) {
func parseReflection(jsonData []byte) ([]InputLocation, []UniformLocation, int, error) {
type InputReflection struct {
ID int `json:"id"`
Name string `json:"name"`
@@ -221,14 +224,14 @@ func parseReflection(jsonData []byte) ([]InputLocation, []UniformLocation, error
}
var reflect shaderMetadata
if err := json.Unmarshal(jsonData, &reflect); err != nil {
return nil, nil, fmt.Errorf("parseReflection: %v", err)
return 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, err
return nil, nil, 0, fmt.Errorf("parseReflection: %v", err)
}
inputs = append(inputs, InputLocation{
Name: input.Name,
@@ -247,22 +250,24 @@ func parseReflection(jsonData []byte) ([]InputLocation, []UniformLocation, error
if len(shaderBlocks) == 0 {
shaderBlocks = reflect.FS.UniformBuffers
}
blockOffset := 0
for _, block := range shaderBlocks {
for _, member := range block.Members {
dataType, size, err := parseDataType(member.Type)
if err != nil {
return nil, nil, err
return nil, nil, 0, fmt.Errorf("parseReflection: %v", err)
}
ublocks = append(ublocks, UniformLocation{
// Synthetic name generated by glslcc.
Name: fmt.Sprintf("_%d.%s", block.ID, member.Name),
Type: dataType,
Size: size,
Offset: member.Offset,
Offset: blockOffset + member.Offset,
})
}
blockOffset += block.Size
}
return inputs, ublocks, nil
return inputs, ublocks, blockOffset, nil
}
func parseDataType(t string) (DataType, int, error) {