diff --git a/gl/dll_windows.go b/gl/dll_windows.go index 50e6257..1afc5f8 100644 --- a/gl/dll_windows.go +++ b/gl/dll_windows.go @@ -7,6 +7,7 @@ package gl import ( "archive/tar" "compress/gzip" + "debug/pe" "fmt" "io" "io/ioutil" @@ -20,7 +21,7 @@ import ( var debug = log.New(ioutil.Discard, "gl: ", log.LstdFlags) func downloadDLLs() (path string, err error) { - url := "https://dl.google.com/go/mobile/angle-dd5c5b-" + runtime.GOARCH + ".tgz" + url := "https://dl.google.com/go/mobile/angle-bd3f8780b-" + runtime.GOARCH + ".tgz" debug.Printf("downloading %s", url) resp, err := http.Get(url) if err != nil { @@ -42,7 +43,7 @@ func downloadDLLs() (path string, err error) { return "", fmt.Errorf("gl: error reading gzip from %v: %v", url, err) } tr := tar.NewReader(r) - var bytesGLESv2, bytesEGL []byte + var bytesGLESv2, bytesEGL, bytesD3DCompiler []byte for { header, err := tr.Next() if err == io.EOF { @@ -56,14 +57,16 @@ func downloadDLLs() (path string, err error) { bytesGLESv2, err = ioutil.ReadAll(tr) case "angle-" + runtime.GOARCH + "/libegl.dll": bytesEGL, err = ioutil.ReadAll(tr) + case "angle-" + runtime.GOARCH + "/d3dcompiler_47.dll": + bytesD3DCompiler, err = ioutil.ReadAll(tr) default: // skip } if err != nil { return "", fmt.Errorf("gl: error reading %v from %v: %v", header.Name, url, err) } } - if len(bytesGLESv2) == 0 || len(bytesEGL) == 0 { - return "", fmt.Errorf("gl: did not find both DLLs in %v", url) + if len(bytesGLESv2) == 0 || len(bytesEGL) == 0 || len(bytesD3DCompiler) == 0 { + return "", fmt.Errorf("gl: did not find all DLLs in %v", url) } writeDLLs := func(path string) error { @@ -73,6 +76,9 @@ func downloadDLLs() (path string, err error) { if err := ioutil.WriteFile(filepath.Join(path, "libegl.dll"), bytesEGL, 0755); err != nil { return fmt.Errorf("gl: cannot install ANGLE: %v", err) } + if err := ioutil.WriteFile(filepath.Join(path, "d3dcompiler_47.dll"), bytesD3DCompiler, 0755); err != nil { + return fmt.Errorf("gl: cannot install ANGLE: %v", err) + } return nil } @@ -108,16 +114,84 @@ func appdataPath() string { return filepath.Join(os.Getenv("LOCALAPPDATA"), "GoGL", runtime.GOARCH) } +func containsDLLs(dir string) bool { + compatible := func(name string) bool { + file, err := pe.Open(filepath.Join(dir, name)) + if err != nil { + return false + } + defer file.Close() + + switch file.Machine { + case pe.IMAGE_FILE_MACHINE_AMD64: + return "amd64" == runtime.GOARCH + case pe.IMAGE_FILE_MACHINE_ARM: + return "arm" == runtime.GOARCH + case pe.IMAGE_FILE_MACHINE_I386: + return "386" == runtime.GOARCH + } + return false + } + + return compatible("libglesv2.dll") && compatible("libegl.dll") && compatible("d3dcompiler_47.dll") +} + +func chromePath() string { + // dlls are stored in: + // //libglesv2.dll + + var installdirs = []string{ + // Chrome User + filepath.Join(os.Getenv("LOCALAPPDATA"), "Google", "Chrome", "Application"), + // Chrome System + filepath.Join(os.Getenv("ProgramFiles(x86)"), "Google", "Chrome", "Application"), + // Chromium + filepath.Join(os.Getenv("LOCALAPPDATA"), "Chromium", "Application"), + // Chrome Canary + filepath.Join(os.Getenv("LOCALAPPDATA"), "Google", "Chrome SxS", "Application"), + } + + for _, installdir := range installdirs { + versiondirs, err := ioutil.ReadDir(installdir) + if err != nil { + continue + } + + for _, versiondir := range versiondirs { + if !versiondir.IsDir() { + continue + } + + versionpath := filepath.Join(installdir, versiondir.Name()) + if containsDLLs(versionpath) { + return versionpath + } + } + } + + return "" +} + func findDLLs() (err error) { load := func(path string) (bool, error) { if path != "" { + // don't try to start when one of the files is missing + if !containsDLLs(path) { + return false, nil + } + + LibD3DCompiler.Name = filepath.Join(path, filepath.Base(LibD3DCompiler.Name)) LibGLESv2.Name = filepath.Join(path, filepath.Base(LibGLESv2.Name)) LibEGL.Name = filepath.Join(path, filepath.Base(LibEGL.Name)) } + if err := LibGLESv2.Load(); err == nil { if err := LibEGL.Load(); err != nil { return false, fmt.Errorf("gl: loaded libglesv2 but not libegl: %v", err) } + if err := LibD3DCompiler.Load(); err != nil { + return false, fmt.Errorf("gl: loaded libglesv2, libegl but not d3dcompiler: %v", err) + } if path == "" { debug.Printf("DLLs found") } else { @@ -125,6 +199,7 @@ func findDLLs() (err error) { } return true, nil } + return false, nil } @@ -138,7 +213,12 @@ func findDLLs() (err error) { return err } - // TODO: Look for a Chrome installation. + // Look for a Chrome installation + if dir := chromePath(); dir != "" { + if ok, err := load(dir); ok || err != nil { + return err + } + } // Look in GOPATH/pkg. if ok, err := load(filepath.Join(os.Getenv("GOPATH"), "pkg")); ok || err != nil { diff --git a/gl/work_windows.go b/gl/work_windows.go index 53c434e..c2bd09d 100644 --- a/gl/work_windows.go +++ b/gl/work_windows.go @@ -23,6 +23,10 @@ type context struct { func (ctx *context) WorkAvailable() <-chan struct{} { return ctx.workAvailable } +type context3 struct { + *context +} + func NewContext() (Context, Worker) { if err := findDLLs(); err != nil { panic(err) @@ -400,9 +404,12 @@ func (ctx *context) doWork(c call) (ret uintptr) { // // LibEGL is not used directly by the gl package, but is needed by any // driver hoping to use OpenGL ES. +// +// LibD3DCompiler is needed by libglesv2.dll for compiling shaders. var ( - LibGLESv2 = syscall.NewLazyDLL("libglesv2.dll") - LibEGL = syscall.NewLazyDLL("libegl.dll") + LibGLESv2 = syscall.NewLazyDLL("libglesv2.dll") + LibEGL = syscall.NewLazyDLL("libegl.dll") + LibD3DCompiler = syscall.NewLazyDLL("d3dcompiler_47.dll") ) var (