From 7286b075e2fb167c5032baeced144379e4a73c5f Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Wed, 10 Feb 2021 21:57:12 +0100 Subject: [PATCH] internal/cmd/convertshaders: use wine for running the HLSL compiler Signed-off-by: Elias Naur --- internal/cmd/convertshaders/hlsl_noop.go | 9 -- internal/cmd/convertshaders/hlsl_windows.go | 9 -- internal/cmd/convertshaders/main.go | 60 ++++++++++- internal/d3dcompile/compile_windows.go | 106 -------------------- 4 files changed, 57 insertions(+), 127 deletions(-) delete mode 100644 internal/cmd/convertshaders/hlsl_noop.go delete mode 100644 internal/cmd/convertshaders/hlsl_windows.go delete mode 100644 internal/d3dcompile/compile_windows.go diff --git a/internal/cmd/convertshaders/hlsl_noop.go b/internal/cmd/convertshaders/hlsl_noop.go deleted file mode 100644 index 1e2e6cee..00000000 --- a/internal/cmd/convertshaders/hlsl_noop.go +++ /dev/null @@ -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 -} diff --git a/internal/cmd/convertshaders/hlsl_windows.go b/internal/cmd/convertshaders/hlsl_windows.go deleted file mode 100644 index ff294269..00000000 --- a/internal/cmd/convertshaders/hlsl_windows.go +++ /dev/null @@ -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) -} diff --git a/internal/cmd/convertshaders/main.go b/internal/cmd/convertshaders/main.go index 977896cc..1f481a1b 100644 --- a/internal/cmd/convertshaders/main.go +++ b/internal/cmd/convertshaders/main.go @@ -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) { diff --git a/internal/d3dcompile/compile_windows.go b/internal/d3dcompile/compile_windows.go deleted file mode 100644 index 1555acc5..00000000 --- a/internal/d3dcompile/compile_windows.go +++ /dev/null @@ -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, - ) -}