aboutsummaryrefslogtreecommitdiffstats
path: root/Godeps/_workspace/src/github.com/Gustav-Simonsson/go-opencl/cl/program.go
blob: e75f7ee0e2cd5f1d93b6071362b48559f51fac43 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package cl

// #include <stdlib.h>
// #ifdef __APPLE__
// #include "OpenCL/opencl.h"
// #else
// #include "cl.h"
// #endif
import "C"

import (
    "fmt"
    "runtime"
    "unsafe"
)

type BuildError struct {
    Message string
    Device  *Device
}

func (e BuildError) Error() string {
    if e.Device != nil {
        return fmt.Sprintf("cl: build error on %q: %s", e.Device.Name(), e.Message)
    } else {
        return fmt.Sprintf("cl: build error: %s", e.Message)
    }
}

type Program struct {
    clProgram C.cl_program
    devices   []*Device
}

func releaseProgram(p *Program) {
    if p.clProgram != nil {
        C.clReleaseProgram(p.clProgram)
        p.clProgram = nil
    }
}

func (p *Program) Release() {
    releaseProgram(p)
}

func (p *Program) BuildProgram(devices []*Device, options string) error {
    var cOptions *C.char
    if options != "" {
        cOptions = C.CString(options)
        defer C.free(unsafe.Pointer(cOptions))
    }
    var deviceList []C.cl_device_id
    var deviceListPtr *C.cl_device_id
    numDevices := C.cl_uint(len(devices))
    if devices != nil && len(devices) > 0 {
        deviceList = buildDeviceIdList(devices)
        deviceListPtr = &deviceList[0]
    }
    if err := C.clBuildProgram(p.clProgram, numDevices, deviceListPtr, cOptions, nil, nil); err != C.CL_SUCCESS {
        buffer := make([]byte, 4096)
        var bLen C.size_t
        var err C.cl_int

        for _, dev := range p.devices {
            for i := 2; i >= 0; i-- {
                err = C.clGetProgramBuildInfo(p.clProgram, dev.id, C.CL_PROGRAM_BUILD_LOG, C.size_t(len(buffer)), unsafe.Pointer(&buffer[0]), &bLen)
                if err == C.CL_INVALID_VALUE && i > 0 && bLen < 1024*1024 {
                    // INVALID_VALUE probably means our buffer isn't large enough
                    buffer = make([]byte, bLen)
                } else {
                    break
                }
            }
            if err != C.CL_SUCCESS {
                return toError(err)
            }

            if bLen > 1 {
                return BuildError{
                    Device:  dev,
                    Message: string(buffer[:bLen-1]),
                }
            }
        }

        return BuildError{
            Device:  nil,
            Message: "build failed and produced no log entries",
        }
    }
    return nil
}

func (p *Program) CreateKernel(name string) (*Kernel, error) {
    cName := C.CString(name)
    defer C.free(unsafe.Pointer(cName))
    var err C.cl_int
    clKernel := C.clCreateKernel(p.clProgram, cName, &err)
    if err != C.CL_SUCCESS {
        return nil, toError(err)
    }
    kernel := &Kernel{clKernel: clKernel, name: name}
    runtime.SetFinalizer(kernel, releaseKernel)
    return kernel, nil
}