internal/cmd/convertshaders: use wine for running the HLSL compiler

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2021-02-10 21:57:12 +01:00
parent 8ec47dcae3
commit 7286b075e2
4 changed files with 57 additions and 127 deletions
-9
View File
@@ -1,9 +0,0 @@
// SPDX-License-Identifier: Unlicense OR MIT
// +build !windows
package main
func compileHLSL(src, entry, profile string) ([]byte, error) {
return nil, nil
}
@@ -1,9 +0,0 @@
// SPDX-License-Identifier: Unlicense OR MIT
package main
import "gioui.org/internal/d3dcompile"
func compileHLSL(src, entry, profile string) ([]byte, error) {
return d3dcompile.D3DCompile([]byte(src), entry, profile)
}
+57 -3
View File
@@ -12,6 +12,7 @@ import (
"os"
"os/exec"
"path/filepath"
"runtime"
"sort"
"strings"
"text/template"
@@ -166,12 +167,12 @@ func generateShader(glslcc, tmp string, out io.Writer, shader string) error {
return fmt.Errorf("unrecognized shader type %s", shader)
}
var hlslc []byte
hlslc, err = compileHLSL(hlsl, "main", hlslProf+"_4_0_level_9_1")
hlslc, err = compileHLSL(tmp, shader, hlsl, "main", hlslProf+"_4_0_level_9_1")
if err != nil {
// Attempt shader model 4.0. Only the app/headless
// test shaders use features not supported by level
// 9.1.
hlslc, err = compileHLSL(hlsl, "main", hlslProf+"_4_0")
hlslc, err = compileHLSL(tmp, shader, hlsl, "main", hlslProf+"_4_0")
if err != nil {
return err
}
@@ -372,6 +373,59 @@ func parseDataType(t string) (backend.DataType, int, error) {
}
}
func compileHLSL(tmp, path, src, entry, profile string) ([]byte, error) {
base := filepath.Base(path)
tmppath := filepath.Join(tmp, base)
defer os.Remove(tmppath)
if err := ioutil.WriteFile(tmppath, []byte(src), 0644); err != nil {
return nil, err
}
outfile := filepath.Join(tmp, base+".obj")
defer os.Remove(outfile)
fxcInput := tmppath
fxcOutput := outfile
var fxc *exec.Cmd
if runtime.GOOS == "windows" {
fxc = exec.Command("fxc.exe")
} else {
// Convert paths to wine Windows format.
var err error
fxcInput, err = windowsPath(fxcInput)
if err != nil {
return nil, err
}
fxcOutput, err = windowsPath(fxcOutput)
if err != nil {
return nil, err
}
fxc = exec.Command("wine", "fxc.exe")
}
var stdout, stderr bytes.Buffer
fxc.Stderr = &stderr
fxc.Stdout = &stdout
fxc.Args = append(fxc.Args, "/Fo", fxcOutput, "/T", profile, "/E", entry, fxcInput)
if err := fxc.Run(); 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 nil, fmt.Errorf("%s\n%s\n%s%s: %v", stderr.Bytes(), stdout.Bytes(), info, fxc, err)
}
return ioutil.ReadFile(outfile)
}
// windowsPath uses the winepath tool to convert a path to Windows format. The returned
// path can be used as arguments for Windows command line tools.
func windowsPath(path string) (string, error) {
var out bytes.Buffer
winepath := exec.Command("winepath", "--windows", path)
winepath.Stdout = &out
if err := winepath.Run(); err != nil {
return "", err
}
return strings.TrimSpace(out.String()), nil
}
func convertShader(tmp, glslcc, path, lang, profile string, args *shaderArgs, flattenUBOs bool) (string, []byte, error) {
shaderTmpl, err := template.ParseFiles(path)
if err != nil {
@@ -382,10 +436,10 @@ func convertShader(tmp, glslcc, path, lang, profile string, args *shaderArgs, fl
return "", nil, err
}
tmppath := filepath.Join(tmp, filepath.Base(path))
defer os.Remove(tmppath)
if err := ioutil.WriteFile(tmppath, buf.Bytes(), 0644); err != nil {
return "", nil, err
}
defer os.Remove(tmppath)
var progFlag string
var progSuffix string
switch filepath.Ext(path) {
-106
View File
@@ -1,106 +0,0 @@
// SPDX-License-Identifier: Unlicense OR MIT
package d3dcompile
import (
"fmt"
"syscall"
"unsafe"
gunsafe "gioui.org/internal/unsafe"
"golang.org/x/sys/windows"
)
var (
d3dcompiler_47 = windows.NewLazySystemDLL("d3dcompiler_47.dll")
__D3DCompile = d3dcompiler_47.NewProc("D3DCompile")
)
type _IUnknownVTbl struct {
QueryInterface uintptr
AddRef uintptr
Release uintptr
}
type _ID3DBlob struct {
vtbl *struct {
_IUnknownVTbl
GetBufferPointer uintptr
GetBufferSize uintptr
}
}
func D3DCompile(src []byte, entryPoint, target string) ([]byte, error) {
var (
code *_ID3DBlob
errors *_ID3DBlob
)
entryPoint0 := []byte(entryPoint + "\x00")
target0 := []byte(target + "\x00")
r, _, _ := __D3DCompile.Call(
uintptr(unsafe.Pointer(&src[0])),
uintptr(len(src)),
0, // pSourceName
0, // pDefines
0, // pInclude
uintptr(unsafe.Pointer(&entryPoint0[0])),
uintptr(unsafe.Pointer(&target0[0])),
0, // Flags1
0, // Flags2
uintptr(unsafe.Pointer(&code)),
uintptr(unsafe.Pointer(&errors)),
)
var compileErr string
if errors != nil {
compileErr = string(errors.data())
_IUnknownRelease(unsafe.Pointer(errors), errors.vtbl.Release)
}
if r != 0 {
return nil, fmt.Errorf("D3D11Compile: %#x: %s", r, compileErr)
}
bytecode := code.data()
cp := make([]byte, len(bytecode))
copy(cp, bytecode)
_IUnknownRelease(unsafe.Pointer(code), code.vtbl.Release)
return cp, nil
}
func (b *_ID3DBlob) GetBufferPointer() uintptr {
ptr, _, _ := syscall.Syscall(
b.vtbl.GetBufferPointer,
1,
uintptr(unsafe.Pointer(b)),
0,
0,
)
return ptr
}
func (b *_ID3DBlob) GetBufferSize() uintptr {
sz, _, _ := syscall.Syscall(
b.vtbl.GetBufferSize,
1,
uintptr(unsafe.Pointer(b)),
0,
0,
)
return sz
}
func (b *_ID3DBlob) data() []byte {
data := gunsafe.SliceOf(b.GetBufferPointer())
n := int(b.GetBufferSize())
return data[:n:n]
}
func _IUnknownRelease(obj unsafe.Pointer, releaseMethod uintptr) {
syscall.Syscall(
releaseMethod,
1,
uintptr(obj),
0,
0,
)
}