mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-01 07:35:40 +00:00
e9a020f774
The recent changes to the compute shaders have fixed all errors previously reported by fxc. Switch from dxc to fxc to target shader model 5.0, supported by Direct3D 11. Because we know dxc must be available, always build compute shaders even though the result is not yet used. Signed-off-by: Elias Naur <mail@eliasnaur.com>
147 lines
3.6 KiB
Go
147 lines
3.6 KiB
Go
// SPDX-License-Identifier: Unlicense OR MIT
|
|
|
|
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
)
|
|
|
|
// FXC is hlsl compiler that targets ShaderModel 5.x and lower.
|
|
type FXC struct {
|
|
Bin string
|
|
WorkDir WorkDir
|
|
}
|
|
|
|
func NewFXC() *FXC { return &FXC{Bin: "fxc.exe"} }
|
|
|
|
// Compile compiles the input shader.
|
|
func (fxc *FXC) Compile(path, variant string, input []byte, entryPoint string, profileVersion string) (string, error) {
|
|
base := fxc.WorkDir.Path(filepath.Base(path), variant, profileVersion)
|
|
pathin := base + ".in"
|
|
pathout := base + ".out"
|
|
result := pathout
|
|
|
|
if err := fxc.WorkDir.WriteFile(pathin, input); err != nil {
|
|
return "", fmt.Errorf("unable to write shader to disk: %w", err)
|
|
}
|
|
|
|
cmd := exec.Command(fxc.Bin)
|
|
if runtime.GOOS != "windows" {
|
|
cmd = exec.Command("wine", fxc.Bin)
|
|
if err := winepath(&pathin, &pathout); err != nil {
|
|
return "", err
|
|
}
|
|
}
|
|
|
|
var profile string
|
|
switch filepath.Ext(path) {
|
|
case ".frag":
|
|
profile = "ps_" + profileVersion
|
|
case ".vert":
|
|
profile = "vs_" + profileVersion
|
|
case ".comp":
|
|
profile = "cs_" + profileVersion
|
|
default:
|
|
return "", fmt.Errorf("unrecognized shader type %s", path)
|
|
}
|
|
|
|
cmd.Args = append(cmd.Args,
|
|
"/Fo", pathout,
|
|
"/T", profile,
|
|
"/E", entryPoint,
|
|
pathin,
|
|
)
|
|
|
|
output, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
info := ""
|
|
if runtime.GOOS != "windows" {
|
|
info = "If the fxc tool cannot be found, set WINEPATH to the Windows path for the Windows SDK.\n"
|
|
}
|
|
return "", fmt.Errorf("%s\n%sfailed to run %v: %w", output, info, cmd.Args, err)
|
|
}
|
|
|
|
compiled, err := ioutil.ReadFile(result)
|
|
if err != nil {
|
|
return "", fmt.Errorf("unable to read output %q: %w", pathout, err)
|
|
}
|
|
|
|
return string(compiled), nil
|
|
}
|
|
|
|
// DXC is hlsl compiler that targets ShaderModel 6.0 and newer.
|
|
type DXC struct {
|
|
Bin string
|
|
WorkDir WorkDir
|
|
}
|
|
|
|
func NewDXC() *DXC { return &DXC{Bin: "dxc"} }
|
|
|
|
// Compile compiles the input shader.
|
|
func (dxc *DXC) Compile(path, variant string, input []byte, entryPoint string, profile string) (string, error) {
|
|
base := dxc.WorkDir.Path(filepath.Base(path), variant, profile)
|
|
pathin := base + ".in"
|
|
pathout := base + ".out"
|
|
result := pathout
|
|
|
|
if err := dxc.WorkDir.WriteFile(pathin, input); err != nil {
|
|
return "", fmt.Errorf("unable to write shader to disk: %w", err)
|
|
}
|
|
|
|
cmd := exec.Command(dxc.Bin)
|
|
|
|
cmd.Args = append(cmd.Args,
|
|
"-Fo", pathout,
|
|
"-T", profile,
|
|
"-E", entryPoint,
|
|
"-Qstrip_reflect",
|
|
pathin,
|
|
)
|
|
|
|
output, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
return "", fmt.Errorf("%s\nfailed to run %v: %w", output, cmd.Args, err)
|
|
}
|
|
|
|
compiled, err := ioutil.ReadFile(result)
|
|
if err != nil {
|
|
return "", fmt.Errorf("unable to read output %q: %w", pathout, err)
|
|
}
|
|
|
|
return string(compiled), nil
|
|
}
|
|
|
|
// winepath uses the winepath tool to convert a paths to Windows format.
|
|
// The returned path can be used as arguments for Windows command line tools.
|
|
func winepath(paths ...*string) error {
|
|
winepath := exec.Command("winepath", "--windows")
|
|
for _, path := range paths {
|
|
winepath.Args = append(winepath.Args, *path)
|
|
}
|
|
// Use a pipe instead of Output, because winepath may have left wineserver
|
|
// running for several seconds as a grandchild.
|
|
out, err := winepath.StdoutPipe()
|
|
if err != nil {
|
|
return fmt.Errorf("unable to start winepath: %w", err)
|
|
}
|
|
if err := winepath.Start(); err != nil {
|
|
return fmt.Errorf("unable to start winepath: %w", err)
|
|
}
|
|
var buf bytes.Buffer
|
|
if _, err := io.Copy(&buf, out); err != nil {
|
|
return fmt.Errorf("unable to run winepath: %w", err)
|
|
}
|
|
winPaths := strings.Split(strings.TrimSpace(buf.String()), "\n")
|
|
for i, path := range paths {
|
|
*path = winPaths[i]
|
|
}
|
|
return nil
|
|
}
|