gl: download ANGLE if necessary
For golang/go#9306 Change-Id: Ibb469d843d2bddeaa3690c59bc9ad532ea3473f7 Reviewed-on: https://go-review.googlesource.com/17810 Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
This commit is contained in:
parent
ab5e5f68d8
commit
6da7fa8e54
163
gl/dll_windows.go
Normal file
163
gl/dll_windows.go
Normal file
@ -0,0 +1,163 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package gl
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
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"
|
||||
debug.Printf("downloading %s", url)
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("gl: %v", err)
|
||||
}
|
||||
defer func() {
|
||||
err2 := resp.Body.Close()
|
||||
if err == nil && err2 != nil {
|
||||
err = fmt.Errorf("gl: error reading body from %v: %v", url, err2)
|
||||
}
|
||||
}()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
err := fmt.Errorf("gl: error fetching %v, status: %v", url, resp.Status)
|
||||
return "", err
|
||||
}
|
||||
|
||||
r, err := gzip.NewReader(resp.Body)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("gl: error reading gzip from %v: %v", url, err)
|
||||
}
|
||||
tr := tar.NewReader(r)
|
||||
var bytesGLESv2, bytesEGL []byte
|
||||
for {
|
||||
header, err := tr.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("gl: error reading tar from %v: %v", url, err)
|
||||
}
|
||||
switch header.Name {
|
||||
case "angle-" + runtime.GOARCH + "/libglesv2.dll":
|
||||
bytesGLESv2, err = ioutil.ReadAll(tr)
|
||||
case "angle-" + runtime.GOARCH + "/libegl.dll":
|
||||
bytesEGL, 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)
|
||||
}
|
||||
|
||||
writeDLLs := func(path string) error {
|
||||
if err := ioutil.WriteFile(filepath.Join(path, "libglesv2.dll"), bytesGLESv2, 0755); err != nil {
|
||||
return fmt.Errorf("gl: cannot install ANGLE: %v", err)
|
||||
}
|
||||
if err := ioutil.WriteFile(filepath.Join(path, "libegl.dll"), bytesEGL, 0755); err != nil {
|
||||
return fmt.Errorf("gl: cannot install ANGLE: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// First, we attempt to install these DLLs in LOCALAPPDATA/Shiny.
|
||||
//
|
||||
// Traditionally we would use the system32 directory, but it is
|
||||
// no longer writable by normal programs.
|
||||
os.MkdirAll(appdataPath(), 0775)
|
||||
if err := writeDLLs(appdataPath()); err == nil {
|
||||
return appdataPath(), nil
|
||||
}
|
||||
debug.Printf("DLLs could not be written to %s", appdataPath())
|
||||
|
||||
// Second, install in GOPATH/pkg if it exists.
|
||||
gopath := os.Getenv("GOPATH")
|
||||
gopathpkg := filepath.Join(gopath, "pkg")
|
||||
if _, err := os.Stat(gopathpkg); err == nil && gopath != "" {
|
||||
if err := writeDLLs(gopathpkg); err == nil {
|
||||
return gopathpkg, nil
|
||||
}
|
||||
}
|
||||
debug.Printf("DLLs could not be written to GOPATH")
|
||||
|
||||
// Third, pick a temporary directory.
|
||||
tmp := os.TempDir()
|
||||
if err := writeDLLs(tmp); err != nil {
|
||||
return "", fmt.Errorf("gl: unable to install ANGLE DLLs: %v", err)
|
||||
}
|
||||
return tmp, nil
|
||||
}
|
||||
|
||||
func appdataPath() string {
|
||||
return filepath.Join(os.Getenv("LOCALAPPDATA"), "GoGL", runtime.GOARCH)
|
||||
}
|
||||
|
||||
func findDLLs() (err error) {
|
||||
load := func(path string) (bool, error) {
|
||||
if path != "" {
|
||||
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 path == "" {
|
||||
debug.Printf("DLLs found")
|
||||
} else {
|
||||
debug.Printf("DLLs found in: %q", path)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Look in the system directory.
|
||||
if ok, err := load(""); ok || err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Look in the AppData directory.
|
||||
if ok, err := load(appdataPath()); ok || err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: Look for a Chrome installation.
|
||||
|
||||
// Look in GOPATH/pkg.
|
||||
if ok, err := load(filepath.Join(os.Getenv("GOPATH"), "pkg")); ok || err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Look in temporary directory.
|
||||
if ok, err := load(os.TempDir()); ok || err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Download the DLL binary.
|
||||
path, err := downloadDLLs()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
debug.Printf("DLLs written to %s", path)
|
||||
if ok, err := load(path); !ok || err != nil {
|
||||
return fmt.Errorf("gl: unable to load ANGLE after installation: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
@ -24,6 +24,9 @@ type context struct {
|
||||
func (ctx *context) WorkAvailable() <-chan struct{} { return ctx.workAvailable }
|
||||
|
||||
func NewContext() (Context, Worker) {
|
||||
if err := findDLLs(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
glctx := &context{
|
||||
workAvailable: make(chan struct{}, 1),
|
||||
work: make(chan call, 3),
|
||||
@ -393,10 +396,17 @@ func (ctx *context) doWork(c call) (ret uintptr) {
|
||||
return ret
|
||||
}
|
||||
|
||||
// TODO: export LibGLESv2/LibEGL lazy DLLs, and come up with a loading scheme.
|
||||
// Exported libraries for a Windows GUI driver.
|
||||
//
|
||||
// LibEGL is not used directly by the gl package, but is needed by any
|
||||
// driver hoping to use OpenGL ES.
|
||||
var (
|
||||
LibGLESv2 = syscall.NewLazyDLL("libglesv2.dll")
|
||||
LibEGL = syscall.NewLazyDLL("libegl.dll")
|
||||
)
|
||||
|
||||
var (
|
||||
libGLESv2 = syscall.NewLazyDLL("libGLESv2.dll")
|
||||
libGLESv2 = LibGLESv2
|
||||
glActiveTexture = libGLESv2.NewProc("glActiveTexture")
|
||||
glAttachShader = libGLESv2.NewProc("glAttachShader")
|
||||
glBindAttribLocation = libGLESv2.NewProc("glBindAttribLocation")
|
||||
|
Loading…
x
Reference in New Issue
Block a user