1 //
2 // Copyright 2012 Francisco Jerez
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a
5 // copy of this software and associated documentation files (the "Software"),
6 // to deal in the Software without restriction, including without limitation
7 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 // and/or sell copies of the Software, and to permit persons to whom the
9 // Software is furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 // THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19 // OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 // SOFTWARE.
21 //
22 
23 #include "core/device.hpp"
24 #include "pipe/p_screen.h"
25 #include "pipe/p_state.h"
26 
27 using namespace clover;
28 
29 namespace {
30    template<typename T>
31    std::vector<T>
get_compute_param(pipe_screen * pipe,pipe_compute_cap cap)32    get_compute_param(pipe_screen *pipe, pipe_compute_cap cap) {
33       int sz = pipe->get_compute_param(pipe, cap, NULL);
34       std::vector<T> v(sz / sizeof(T));
35 
36       pipe->get_compute_param(pipe, cap, &v.front());
37       return v;
38    }
39 }
40 
_cl_device_id(pipe_loader_device * ldev)41 _cl_device_id::_cl_device_id(pipe_loader_device *ldev) : ldev(ldev) {
42    pipe = pipe_loader_create_screen(ldev, PIPE_SEARCH_DIR);
43    if (!pipe || !pipe->get_param(pipe, PIPE_CAP_COMPUTE))
44       throw error(CL_INVALID_DEVICE);
45 }
46 
_cl_device_id(_cl_device_id && dev)47 _cl_device_id::_cl_device_id(_cl_device_id &&dev) : pipe(dev.pipe), ldev(dev.ldev) {
48    dev.ldev = NULL;
49    dev.pipe = NULL;
50 }
51 
~_cl_device_id()52 _cl_device_id::~_cl_device_id() {
53    if (pipe)
54       pipe->destroy(pipe);
55    if (ldev)
56       pipe_loader_release(&ldev, 1);
57 }
58 
59 cl_device_type
type() const60 _cl_device_id::type() const {
61    switch (ldev->type) {
62    case PIPE_LOADER_DEVICE_SOFTWARE:
63       return CL_DEVICE_TYPE_CPU;
64    case PIPE_LOADER_DEVICE_PCI:
65       return CL_DEVICE_TYPE_GPU;
66    default:
67       assert(0);
68       return 0;
69    }
70 }
71 
72 cl_uint
vendor_id() const73 _cl_device_id::vendor_id() const {
74    switch (ldev->type) {
75    case PIPE_LOADER_DEVICE_SOFTWARE:
76       return 0;
77    case PIPE_LOADER_DEVICE_PCI:
78       return ldev->u.pci.vendor_id;
79    default:
80       assert(0);
81       return 0;
82    }
83 }
84 
85 size_t
max_images_read() const86 _cl_device_id::max_images_read() const {
87    return PIPE_MAX_SHADER_RESOURCES;
88 }
89 
90 size_t
max_images_write() const91 _cl_device_id::max_images_write() const {
92    return PIPE_MAX_SHADER_RESOURCES;
93 }
94 
95 cl_uint
max_image_levels_2d() const96 _cl_device_id::max_image_levels_2d() const {
97    return pipe->get_param(pipe, PIPE_CAP_MAX_TEXTURE_2D_LEVELS);
98 }
99 
100 cl_uint
max_image_levels_3d() const101 _cl_device_id::max_image_levels_3d() const {
102    return pipe->get_param(pipe, PIPE_CAP_MAX_TEXTURE_3D_LEVELS);
103 }
104 
105 cl_uint
max_samplers() const106 _cl_device_id::max_samplers() const {
107    return pipe->get_shader_param(pipe, PIPE_SHADER_COMPUTE,
108                                  PIPE_SHADER_CAP_MAX_TEXTURE_SAMPLERS);
109 }
110 
111 cl_ulong
max_mem_global() const112 _cl_device_id::max_mem_global() const {
113    return get_compute_param<uint64_t>(pipe,
114                                       PIPE_COMPUTE_CAP_MAX_GLOBAL_SIZE)[0];
115 }
116 
117 cl_ulong
max_mem_local() const118 _cl_device_id::max_mem_local() const {
119    return get_compute_param<uint64_t>(pipe,
120                                       PIPE_COMPUTE_CAP_MAX_LOCAL_SIZE)[0];
121 }
122 
123 cl_ulong
max_mem_input() const124 _cl_device_id::max_mem_input() const {
125    return get_compute_param<uint64_t>(pipe,
126                                       PIPE_COMPUTE_CAP_MAX_INPUT_SIZE)[0];
127 }
128 
129 cl_ulong
max_const_buffer_size() const130 _cl_device_id::max_const_buffer_size() const {
131    return pipe->get_shader_param(pipe, PIPE_SHADER_COMPUTE,
132                                  PIPE_SHADER_CAP_MAX_CONSTS) * 16;
133 }
134 
135 cl_uint
max_const_buffers() const136 _cl_device_id::max_const_buffers() const {
137    return pipe->get_shader_param(pipe, PIPE_SHADER_COMPUTE,
138                                  PIPE_SHADER_CAP_MAX_CONST_BUFFERS);
139 }
140 
141 size_t
max_threads_per_block() const142 _cl_device_id::max_threads_per_block() const {
143    return get_compute_param<uint64_t>(
144       pipe, PIPE_COMPUTE_CAP_MAX_THREADS_PER_BLOCK)[0];
145 }
146 
147 std::vector<size_t>
max_block_size() const148 _cl_device_id::max_block_size() const {
149    auto v = get_compute_param<uint64_t>(pipe, PIPE_COMPUTE_CAP_MAX_BLOCK_SIZE);
150    return { v.begin(), v.end() };
151 }
152 
153 std::string
device_name() const154 _cl_device_id::device_name() const {
155    return pipe->get_name(pipe);
156 }
157 
158 std::string
vendor_name() const159 _cl_device_id::vendor_name() const {
160    return pipe->get_vendor(pipe);
161 }
162 
163 enum pipe_shader_ir
ir_format() const164 _cl_device_id::ir_format() const {
165    return (enum pipe_shader_ir) pipe->get_shader_param(pipe,
166                                                   PIPE_SHADER_COMPUTE,
167                                                   PIPE_SHADER_CAP_PREFERRED_IR);
168 }
169 
170 std::string
ir_target() const171 _cl_device_id::ir_target() const {
172    std::vector<char> target = get_compute_param<char>(pipe,
173                                                     PIPE_COMPUTE_CAP_IR_TARGET);
174    return { target.data() };
175 }
176 
device_registry()177 device_registry::device_registry() {
178    int n = pipe_loader_probe(NULL, 0);
179    std::vector<pipe_loader_device *> ldevs(n);
180 
181    pipe_loader_probe(&ldevs.front(), n);
182 
183    for (pipe_loader_device *ldev : ldevs) {
184       try {
185          devs.emplace_back(ldev);
186       } catch (error &) {}
187    }
188 }
189