Commit 689c905d by Philipp Adolf

Initial commit

parents
MIT License
Copyright (c) 2017 Philipp Adolf
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# go-opencl
go-opencl is a wrapper around the C OpenCL 1.2 API for Go. It aims to be close to the C API while adding Go features (object orientation, `[]string` instead of space delimited extension list, etc.).
It is mainly developed and tested on Linux and with Intel and Nvidia GPUs. It should work with AMD GPUs and, at least in theory, it should work on Windows and macOS.
## Features
- [x] querying platforms
- [x] enumerate platforms
- [x] query info
- [ ] querying devices
- [x] enumerate devices of a platform
- [ ] querying info
- [ ] subdevices (not planned for now)
- [ ] context
- [ ] creating and releasing contexts
- [ ] querying info
- [ ] command queues
- [ ] creating and releasing command queues
- [ ] querying info
- [ ] buffers
- [ ] creating and releasing buffers
- [ ] writing buffers
- [ ] reading buffers
- [ ] querying info
- [ ] program objects
- [ ] creating and releasing program objects
- [ ] building program executables
- [ ] separate compiling and linking (not planned for now)
- [ ] unloading the compiler
- [ ] querying program (build) info
- [ ] kernel objects
- [ ] creating and releasing kernels
- [ ] setting arguments
- [ ] querying kernel, work group and argument info
- [ ] executing kernels
- [ ] event objects
- [ ] creating and releasing user events (not planned for now)
- [ ] query event info
- [ ] flush and finish
- [ ] wait for events
- [ ] event callbacks (not planned for now)
- [ ] markers and barriers (not planned for now)
- [ ] profiling info (not planned for now)
- [ ] images (not planned for now)
- [ ] write detailed todo for images
- [ ] Direct3D sharing (not planned for now)
- [ ] OpenGL sharing (not planned for now)
- [ ] DX9 Media Surface sharing (not planned for now)
- [ ] Direct3D 11 sharing (not planned for now)
## Documentation
There isn't too much documentation in this project, however the API mimics the C API (with some object orientation thrown in), so by taking a look at the official OpenCL 1.2 documentation it should be easy enough to understand. Take a look at the included `go-opencl-info` utility to see how to use this API.
package main
import (
"log"
"strings"
"github.com/Patagonicus/opencl"
)
func main() {
platforms, err := opencl.GetPlatforms()
if err != nil {
log.Fatal(err)
}
for i, p := range platforms {
log.Printf("Platform %d", i)
var name, vendor, profile, version string
var extensions []string
var err error
if name, err = p.Name(); err != nil {
log.Fatal(err)
}
if vendor, err = p.Vendor(); err != nil {
log.Fatal(err)
}
if profile, err = p.Profile(); err != nil {
log.Fatal(err)
}
if version, err = p.Version(); err != nil {
log.Fatal(err)
}
if extensions, err = p.Extension(); err != nil {
log.Fatal(err)
}
log.Printf(" Name: %s", name)
log.Printf(" Vendor: %s", vendor)
log.Printf(" Profile: %s", profile)
log.Printf(" Version: %s", version)
log.Printf(" Extensions: %s", strings.Join(extensions, ", "))
}
}
//+build ignore
package main
/*
#ifdef __APPLE__
#include <OpenCL/opencl.h>
#else
#include <CL/cl.h>
#endif
*/
import "C"
import (
"bytes"
"io/ioutil"
"log"
"os"
"text/template"
)
var platformInfo = []struct {
Name string
ID string
ReturnType string
}{
{"Profile", "C.CL_PLATFORM_PROFILE", "string"},
{"Version", "C.CL_PLATFORM_VERSION", "string"},
{"Name", "C.CL_PLATFORM_NAME", "string"},
{"Vendor", "C.CL_PLATFORM_VENDOR", "string"},
{"Extension", "C.CL_PLATFORM_EXTENSIONS", "space-delim"},
}
var templates = []struct {
in string
out string
data interface{}
}{
{"platforminfo.go.tmpl", "platforminfo.go", platformInfo},
}
func loadTemplate(filename string) (*template.Template, error) {
return template.ParseFiles(filename)
}
func generate(tmpl *template.Template, data interface{}) ([]byte, error) {
var buf bytes.Buffer
err := tmpl.Execute(&buf, data)
if err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func writeBytes(filename string, data []byte) error {
return ioutil.WriteFile(filename, data, 0644)
}
func generateInfo(templatename, filename string, data interface{}) error {
tmpl, err := loadTemplate(templatename)
if err != nil {
return err
}
code, err := generate(tmpl, data)
if err != nil {
return err
}
return writeBytes(filename, code)
}
func main() {
for _, t := range templates {
err := generateInfo(t.in, t.out, t.data)
if err != nil {
os.Remove(t.out)
log.Fatal(err)
}
}
}
package opencl
//go:generate go run infogen.go
// #cgo LDFLAGS: -lOpenCL
/*
#ifdef __APPLE__
#include <OpenCL/opencl.h>
#else
#include <CL/cl.h>
#endif
*/
import "C"
package opencl
/*
#ifdef __APPLE__
#include <OpenCL/opencl.h>
#else
#include <CL/cl.h>
#endif
*/
import "C"
import "fmt"
type Platform struct {
id C.cl_platform_id
}
func GetPlatforms() ([]Platform, error) {
var num_platforms C.cl_uint
if err := C.clGetPlatformIDs(0, nil, &num_platforms); err != C.CL_SUCCESS {
return nil, fmt.Errorf("error getting number of platforms: %d", err)
}
ids := make([]C.cl_platform_id, num_platforms)
if err := C.clGetPlatformIDs(num_platforms, &ids[0], nil); err != C.CL_SUCCESS {
return nil, fmt.Errorf("error getting platforms: %d", err)
}
platforms := make([]Platform, num_platforms)
for i, id := range ids {
platforms[i].id = id
}
return platforms, nil
}
// Code generated go generate DO NOT EDIT.
package opencl
/*
#include <stdlib.h>
#ifdef __APPLE__
#include <OpenCL/opencl.h>
#else
#include <CL/cl.h>
#endif
*/
import "C"
import (
"fmt"
"strings"
"unsafe"
)
func (p Platform) getInfoString(name string, id C.cl_platform_info) (string, error) {
var n C.size_t
if err := C.clGetPlatformInfo(p.id, id, 0, nil, &n); err != C.CL_SUCCESS {
return "", fmt.Errorf("error getting length of platform info %s: %d", name, err)
}
buf := make([]C.char, n)
if err := C.clGetPlatformInfo(p.id, id, n, unsafe.Pointer(&buf[0]), nil); err != C.CL_SUCCESS {
return "", fmt.Errorf("error getting platform info %s: %d", name, err)
}
return C.GoString(&buf[0]), nil
}
func (p Platform) dummyUseStrings() ([]string) {
// a dummy function so that strings is not unused even if template space-delim is not used
return strings.Split("", "")
}
func (p Platform) Profile() (string, error) {
return p.getInfoString("Profile", C.CL_PLATFORM_PROFILE)
}
func (p Platform) Version() (string, error) {
return p.getInfoString("Version", C.CL_PLATFORM_VERSION)
}
func (p Platform) Name() (string, error) {
return p.getInfoString("Name", C.CL_PLATFORM_NAME)
}
func (p Platform) Vendor() (string, error) {
return p.getInfoString("Vendor", C.CL_PLATFORM_VENDOR)
}
func (p Platform) Extension() ([]string, error) {
str, err := p.getInfoString("Extension", C.CL_PLATFORM_EXTENSIONS)
if err != nil {
return nil, err
}
return strings.Split(str, " "), nil
}
// Code {{/* not */}}generated go generate DO NOT EDIT.
package opencl
/*
#include <stdlib.h>
#ifdef __APPLE__
#include <OpenCL/opencl.h>
#else
#include <CL/cl.h>
#endif
*/
import "C"
import (
"fmt"
"strings"
"unsafe"
)
func (p Platform) getInfoString(name string, id C.cl_platform_info) (string, error) {
var n C.size_t
if err := C.clGetPlatformInfo(p.id, id, 0, nil, &n); err != C.CL_SUCCESS {
return "", fmt.Errorf("error getting length of platform info %s: %d", name, err)
}
buf := make([]C.char, n)
if err := C.clGetPlatformInfo(p.id, id, n, unsafe.Pointer(&buf[0]), nil); err != C.CL_SUCCESS {
return "", fmt.Errorf("error getting platform info %s: %d", name, err)
}
return C.GoString(&buf[0]), nil
}
func (p Platform) dummyUseStrings() ([]string) {
// a dummy function so that strings is not unused even if template space-delim is not used
return strings.Split("", "")
}
{{define "string"}}func (p Platform) {{.Name}}() (string, error) {
return p.getInfoString({{printf "%#v" .Name}}, {{.ID}})
}
{{end}}
{{define "space-delim"}}func (p Platform) {{.Name}}() ([]string, error) {
str, err := p.getInfoString({{printf "%#v" .Name}}, {{.ID}})
if err != nil {
return nil, err
}
return strings.Split(str, " "), nil
}
{{end}}
{{- range . -}}
{{- if (eq .ReturnType "string")}}{{template "string" .}}
{{- else if (eq .ReturnType "space-delim")}}{{template "space-delim" .}}
{{- else}}Unknown return type {{.ReturnType}} for {{.Name}}{{end}}
{{end -}}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment