forked from joejulian/gio
internal/cmd/convertshaders: add support for compute shaders
Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
@@ -7,6 +7,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@@ -67,9 +68,57 @@ func generate() error {
|
|||||||
out.WriteString("var (\n")
|
out.WriteString("var (\n")
|
||||||
|
|
||||||
for _, shader := range shaders {
|
for _, shader := range shaders {
|
||||||
if ext := filepath.Ext(shader); ext != ".vert" && ext != ".frag" {
|
var err error
|
||||||
|
switch filepath.Ext(shader) {
|
||||||
|
case ".vert", ".frag":
|
||||||
|
err = generateShader(glslcc, tmp, &out, shader)
|
||||||
|
case ".comp":
|
||||||
|
err = generateComputeShader(tmp, &out, shader)
|
||||||
|
default:
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.WriteString(")")
|
||||||
|
if err := ioutil.WriteFile("shaders.go", out.Bytes(), 0644); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cmd := exec.Command("gofmt", "-s", "-w", "shaders.go")
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateComputeShader(tmp string, out io.Writer, shader string) error {
|
||||||
|
glslangValidator, err := exec.LookPath("glslangValidator")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
spirv_cross, err := exec.LookPath("spirv-cross")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var src backend.ShaderSources
|
||||||
|
glsl310es, err := convertComputeShader(tmp, glslangValidator, spirv_cross, shader)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
src.Name = filepath.Base(shader)
|
||||||
|
src.GLSL310ES = glsl310es
|
||||||
|
name := filepath.Base(shader)
|
||||||
|
name = strings.ReplaceAll(name, ".", "_")
|
||||||
|
fmt.Fprintf(out, "\tshader_%s = ", name)
|
||||||
|
fmt.Fprintf(out, "backend.ShaderSources{\n")
|
||||||
|
fmt.Fprintf(out, "Name: %#v,\n", src.Name)
|
||||||
|
fmt.Fprintf(out, "GLSL310ES: %#v,\n", src.GLSL310ES)
|
||||||
|
fmt.Fprintf(out, "}")
|
||||||
|
fmt.Fprintf(out, "\n")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateShader(glslcc, tmp string, out io.Writer, shader string) error {
|
||||||
const nvariants = 3
|
const nvariants = 3
|
||||||
var variants [nvariants]struct {
|
var variants [nvariants]struct {
|
||||||
backend.ShaderSources
|
backend.ShaderSources
|
||||||
@@ -90,14 +139,9 @@ func generate() error {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
for i := range args {
|
for i := range args {
|
||||||
glsl100es, reflect, err := convertShader(tmp, glslcc, shader, "gles", "100", &args[i], false)
|
// Ignore error; some shaders are not meant to run in GLSL 1.00.
|
||||||
if err != nil {
|
glsl100es, _, _ := convertShader(tmp, glslcc, shader, "gles", "100", &args[i], false)
|
||||||
return err
|
glsl300es, reflect, err := convertShader(tmp, glslcc, shader, "gles", "300", &args[i], false)
|
||||||
}
|
|
||||||
if err := parseReflection(reflect, &variants[i].ShaderSources); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
glsl300es, _, err := convertShader(tmp, glslcc, shader, "gles", "300", &args[i], false)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -109,6 +153,9 @@ func generate() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := parseReflection(reflect, &variants[i].ShaderSources); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
var hlslProf string
|
var hlslProf string
|
||||||
switch filepath.Ext(shader) {
|
switch filepath.Ext(shader) {
|
||||||
case ".frag":
|
case ".frag":
|
||||||
@@ -132,6 +179,7 @@ func generate() error {
|
|||||||
// OpenGL 3.2 Core only accepts GLSL version 1.50, but is
|
// OpenGL 3.2 Core only accepts GLSL version 1.50, but is
|
||||||
// otherwise compatible with version 1.30.
|
// otherwise compatible with version 1.30.
|
||||||
glsl150 := strings.Replace(glsl130, "#version 130", "#version 150", 1)
|
glsl150 := strings.Replace(glsl130, "#version 130", "#version 150", 1)
|
||||||
|
variants[i].Name = filepath.Base(shader)
|
||||||
variants[i].GLSL100ES = glsl100es
|
variants[i].GLSL100ES = glsl100es
|
||||||
variants[i].GLSL300ES = glsl300es
|
variants[i].GLSL300ES = glsl300es
|
||||||
variants[i].GLSL130 = glsl130
|
variants[i].GLSL130 = glsl130
|
||||||
@@ -141,55 +189,48 @@ func generate() error {
|
|||||||
}
|
}
|
||||||
name := filepath.Base(shader)
|
name := filepath.Base(shader)
|
||||||
name = strings.ReplaceAll(name, ".", "_")
|
name = strings.ReplaceAll(name, ".", "_")
|
||||||
fmt.Fprintf(&out, "\tshader_%s = ", name)
|
fmt.Fprintf(out, "\tshader_%s = ", name)
|
||||||
// If the shader don't use the variant arguments, output
|
// If the shader don't use the variant arguments, output
|
||||||
// only a single version.
|
// only a single version.
|
||||||
multiVariant := variants[0].GLSL100ES != variants[1].GLSL100ES
|
multiVariant := variants[0].GLSL100ES != variants[1].GLSL100ES
|
||||||
if multiVariant {
|
if multiVariant {
|
||||||
fmt.Fprintf(&out, "[...]backend.ShaderSources{\n")
|
fmt.Fprintf(out, "[...]backend.ShaderSources{\n")
|
||||||
}
|
}
|
||||||
for _, src := range variants {
|
for _, src := range variants {
|
||||||
fmt.Fprintf(&out, "backend.ShaderSources{\n")
|
fmt.Fprintf(out, "backend.ShaderSources{\n")
|
||||||
|
fmt.Fprintf(out, "Name: %#v,\n", src.Name)
|
||||||
if len(src.Inputs) > 0 {
|
if len(src.Inputs) > 0 {
|
||||||
fmt.Fprintf(&out, "Inputs: %#v,\n", src.Inputs)
|
fmt.Fprintf(out, "Inputs: %#v,\n", src.Inputs)
|
||||||
}
|
}
|
||||||
if u := src.Uniforms; len(u.Blocks) > 0 {
|
if u := src.Uniforms; len(u.Blocks) > 0 {
|
||||||
fmt.Fprintf(&out, "Uniforms: backend.UniformsReflection{\n")
|
fmt.Fprintf(out, "Uniforms: backend.UniformsReflection{\n")
|
||||||
fmt.Fprintf(&out, "Blocks: %#v,\n", u.Blocks)
|
fmt.Fprintf(out, "Blocks: %#v,\n", u.Blocks)
|
||||||
fmt.Fprintf(&out, "Locations: %#v,\n", u.Locations)
|
fmt.Fprintf(out, "Locations: %#v,\n", u.Locations)
|
||||||
fmt.Fprintf(&out, "Size: %d,\n", u.Size)
|
fmt.Fprintf(out, "Size: %d,\n", u.Size)
|
||||||
fmt.Fprintf(&out, "},\n")
|
fmt.Fprintf(out, "},\n")
|
||||||
}
|
}
|
||||||
if len(src.Textures) > 0 {
|
if len(src.Textures) > 0 {
|
||||||
fmt.Fprintf(&out, "Textures: %#v,\n", src.Textures)
|
fmt.Fprintf(out, "Textures: %#v,\n", src.Textures)
|
||||||
}
|
}
|
||||||
fmt.Fprintf(&out, "GLSL100ES: %#v,\n", src.GLSL100ES)
|
fmt.Fprintf(out, "GLSL100ES: %#v,\n", src.GLSL100ES)
|
||||||
fmt.Fprintf(&out, "GLSL300ES: %#v,\n", src.GLSL300ES)
|
fmt.Fprintf(out, "GLSL300ES: %#v,\n", src.GLSL300ES)
|
||||||
fmt.Fprintf(&out, "GLSL130: %#v,\n", src.GLSL130)
|
fmt.Fprintf(out, "GLSL130: %#v,\n", src.GLSL130)
|
||||||
fmt.Fprintf(&out, "GLSL150: %#v,\n", src.GLSL150)
|
fmt.Fprintf(out, "GLSL150: %#v,\n", src.GLSL150)
|
||||||
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)
|
||||||
fmt.Fprintf(&out, "}")
|
fmt.Fprintf(out, "}")
|
||||||
if multiVariant {
|
if multiVariant {
|
||||||
fmt.Fprintf(&out, ",")
|
fmt.Fprintf(out, ",")
|
||||||
}
|
}
|
||||||
fmt.Fprintf(&out, "\n")
|
fmt.Fprintf(out, "\n")
|
||||||
if !multiVariant {
|
if !multiVariant {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if multiVariant {
|
if multiVariant {
|
||||||
fmt.Fprintf(&out, "}\n")
|
fmt.Fprintf(out, "}\n")
|
||||||
}
|
}
|
||||||
}
|
return nil
|
||||||
out.WriteString(")")
|
|
||||||
if err := ioutil.WriteFile("shaders.go", out.Bytes(), 0644); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
cmd := exec.Command("gofmt", "-s", "-w", "shaders.go")
|
|
||||||
cmd.Stdout = os.Stdout
|
|
||||||
cmd.Stderr = os.Stderr
|
|
||||||
return cmd.Run()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseReflection(jsonData []byte, info *backend.ShaderSources) error {
|
func parseReflection(jsonData []byte, info *backend.ShaderSources) error {
|
||||||
@@ -223,14 +264,23 @@ func parseReflection(jsonData []byte, info *backend.ShaderSources) error {
|
|||||||
Dimension string `json:"dimension"`
|
Dimension string `json:"dimension"`
|
||||||
Format string `json:"format"`
|
Format string `json:"format"`
|
||||||
}
|
}
|
||||||
|
type StorageBufferReflection struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Set int `json:"set"`
|
||||||
|
Binding int `json:"binding"`
|
||||||
|
BlockSize int `json:"block_size"`
|
||||||
|
}
|
||||||
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"`
|
Textures []TextureReflection `json:"textures"`
|
||||||
|
StorageBuffers []StorageBufferReflection `json:"storage_buffers"`
|
||||||
}
|
}
|
||||||
type shaderMetadata struct {
|
type shaderMetadata struct {
|
||||||
VS shaderReflection `json:"vs"`
|
VS shaderReflection `json:"vs"`
|
||||||
FS shaderReflection `json:"fs"`
|
FS shaderReflection `json:"fs"`
|
||||||
|
CS shaderReflection `json:"cs"`
|
||||||
}
|
}
|
||||||
var reflect shaderMetadata
|
var reflect shaderMetadata
|
||||||
if err := json.Unmarshal(jsonData, &reflect); err != nil {
|
if err := json.Unmarshal(jsonData, &reflect); err != nil {
|
||||||
@@ -290,6 +340,12 @@ func parseReflection(jsonData []byte, info *backend.ShaderSources) error {
|
|||||||
Binding: texture.Binding,
|
Binding: texture.Binding,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
for _, sb := range reflect.CS.StorageBuffers {
|
||||||
|
info.StorageBuffers = append(info.StorageBuffers, backend.StorageBufferBinding{
|
||||||
|
Binding: sb.Binding,
|
||||||
|
BlockSize: sb.BlockSize,
|
||||||
|
})
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -339,6 +395,9 @@ func convertShader(tmp, glslcc, path, lang, profile string, args *shaderArgs, fl
|
|||||||
case ".frag":
|
case ".frag":
|
||||||
progFlag = "--frag"
|
progFlag = "--frag"
|
||||||
progSuffix = "fs"
|
progSuffix = "fs"
|
||||||
|
case ".comp":
|
||||||
|
progFlag = "--compute"
|
||||||
|
progSuffix = "cs"
|
||||||
default:
|
default:
|
||||||
return "", nil, fmt.Errorf("unrecognized shader type: %s", path)
|
return "", nil, fmt.Errorf("unrecognized shader type: %s", path)
|
||||||
}
|
}
|
||||||
@@ -361,7 +420,7 @@ func convertShader(tmp, glslcc, path, lang, profile string, args *shaderArgs, fl
|
|||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = os.Stderr
|
||||||
if err := cmd.Run(); err != nil {
|
if err := cmd.Run(); err != nil {
|
||||||
return "", nil, fmt.Errorf("%s: %v", path, err)
|
return "", nil, fmt.Errorf("%s: %v", strings.Join(cmd.Args, " "), err)
|
||||||
}
|
}
|
||||||
f, err := os.Open(filepath.Join(tmp, "shader_"+progSuffix))
|
f, err := os.Open(filepath.Join(tmp, "shader_"+progSuffix))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -379,3 +438,31 @@ func convertShader(tmp, glslcc, path, lang, profile string, args *shaderArgs, fl
|
|||||||
}
|
}
|
||||||
return string(src), reflect, nil
|
return string(src), reflect, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func convertComputeShader(tmp, glslangValidator, spirv_cross, path string) (string, error) {
|
||||||
|
spvFile := filepath.Join(tmp, "shader.spv")
|
||||||
|
cmd := exec.Command(glslangValidator,
|
||||||
|
"-G100", // OpenGL ES 3.1.
|
||||||
|
"-w", // Suppress warnings.
|
||||||
|
"-o", spvFile,
|
||||||
|
path,
|
||||||
|
)
|
||||||
|
defer os.Remove(spvFile)
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
return "", fmt.Errorf("%s: %v", strings.Join(cmd.Args, " "), err)
|
||||||
|
}
|
||||||
|
cmd = exec.Command(spirv_cross,
|
||||||
|
"--es",
|
||||||
|
"--version", "310",
|
||||||
|
spvFile,
|
||||||
|
)
|
||||||
|
var shaderDump bytes.Buffer
|
||||||
|
cmd.Stdout = &shaderDump
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
return "", fmt.Errorf("%s: %v", strings.Join(cmd.Args, " "), err)
|
||||||
|
}
|
||||||
|
return shaderDump.String(), nil
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user