1 //
2 // Copyright 2021 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // CLKernelCL.cpp: Implements the class methods for CLKernelCL.
7
8 #include "libANGLE/renderer/cl/CLKernelCL.h"
9
10 #include "libANGLE/renderer/cl/CLCommandQueueCL.h"
11 #include "libANGLE/renderer/cl/CLContextCL.h"
12 #include "libANGLE/renderer/cl/CLDeviceCL.h"
13 #include "libANGLE/renderer/cl/CLMemoryCL.h"
14 #include "libANGLE/renderer/cl/CLSamplerCL.h"
15
16 #include "libANGLE/CLCommandQueue.h"
17 #include "libANGLE/CLContext.h"
18 #include "libANGLE/CLKernel.h"
19 #include "libANGLE/CLMemory.h"
20 #include "libANGLE/CLPlatform.h"
21 #include "libANGLE/CLProgram.h"
22 #include "libANGLE/CLSampler.h"
23
24 namespace rx
25 {
26
27 namespace
28 {
29
30 template <typename T>
GetWorkGroupInfo(cl_kernel kernel,cl_device_id device,cl::KernelWorkGroupInfo name,T & value,cl_int & errorCode)31 bool GetWorkGroupInfo(cl_kernel kernel,
32 cl_device_id device,
33 cl::KernelWorkGroupInfo name,
34 T &value,
35 cl_int &errorCode)
36 {
37 errorCode = kernel->getDispatch().clGetKernelWorkGroupInfo(kernel, device, cl::ToCLenum(name),
38 sizeof(T), &value, nullptr);
39 return errorCode == CL_SUCCESS;
40 }
41
42 template <typename T>
GetArgInfo(cl_kernel kernel,cl_uint index,cl::KernelArgInfo name,T & value,cl_int & errorCode)43 bool GetArgInfo(cl_kernel kernel,
44 cl_uint index,
45 cl::KernelArgInfo name,
46 T &value,
47 cl_int &errorCode)
48 {
49 errorCode = kernel->getDispatch().clGetKernelArgInfo(kernel, index, cl::ToCLenum(name),
50 sizeof(T), &value, nullptr);
51 if (errorCode == CL_KERNEL_ARG_INFO_NOT_AVAILABLE)
52 {
53 errorCode = CL_SUCCESS;
54 }
55 return errorCode == CL_SUCCESS;
56 }
57
58 template <typename T>
GetKernelInfo(cl_kernel kernel,cl::KernelInfo name,T & value,cl_int & errorCode)59 bool GetKernelInfo(cl_kernel kernel, cl::KernelInfo name, T &value, cl_int &errorCode)
60 {
61 errorCode = kernel->getDispatch().clGetKernelInfo(kernel, cl::ToCLenum(name), sizeof(T), &value,
62 nullptr);
63 return errorCode == CL_SUCCESS;
64 }
65
GetArgString(cl_kernel kernel,cl_uint index,cl::KernelArgInfo name,std::string & string,cl_int & errorCode)66 bool GetArgString(cl_kernel kernel,
67 cl_uint index,
68 cl::KernelArgInfo name,
69 std::string &string,
70 cl_int &errorCode)
71 {
72 size_t size = 0u;
73 errorCode = kernel->getDispatch().clGetKernelArgInfo(kernel, index, cl::ToCLenum(name), 0u,
74 nullptr, &size);
75 if (errorCode == CL_KERNEL_ARG_INFO_NOT_AVAILABLE)
76 {
77 errorCode = CL_SUCCESS;
78 return true;
79 }
80 else if (errorCode != CL_SUCCESS)
81 {
82 return false;
83 }
84 std::vector<char> valString(size, '\0');
85 errorCode = kernel->getDispatch().clGetKernelArgInfo(kernel, index, cl::ToCLenum(name), size,
86 valString.data(), nullptr);
87 if (errorCode != CL_SUCCESS)
88 {
89 return false;
90 }
91 string.assign(valString.data(), valString.size() - 1u);
92 return true;
93 }
94
GetKernelString(cl_kernel kernel,cl::KernelInfo name,std::string & string,cl_int & errorCode)95 bool GetKernelString(cl_kernel kernel, cl::KernelInfo name, std::string &string, cl_int &errorCode)
96 {
97 size_t size = 0u;
98 errorCode =
99 kernel->getDispatch().clGetKernelInfo(kernel, cl::ToCLenum(name), 0u, nullptr, &size);
100 if (errorCode != CL_SUCCESS)
101 {
102 return false;
103 }
104 std::vector<char> valString(size, '\0');
105 errorCode = kernel->getDispatch().clGetKernelInfo(kernel, cl::ToCLenum(name), size,
106 valString.data(), nullptr);
107 if (errorCode != CL_SUCCESS)
108 {
109 return false;
110 }
111 string.assign(valString.data(), valString.size() - 1u);
112 return true;
113 }
114
115 } // namespace
116
CLKernelCL(const cl::Kernel & kernel,cl_kernel native)117 CLKernelCL::CLKernelCL(const cl::Kernel &kernel, cl_kernel native)
118 : CLKernelImpl(kernel), mNative(native)
119 {}
120
~CLKernelCL()121 CLKernelCL::~CLKernelCL()
122 {
123 if (mNative->getDispatch().clReleaseKernel(mNative) != CL_SUCCESS)
124 {
125 ERR() << "Error while releasing CL kernel";
126 }
127 }
128
setArg(cl_uint argIndex,size_t argSize,const void * argValue)129 cl_int CLKernelCL::setArg(cl_uint argIndex, size_t argSize, const void *argValue)
130 {
131 void *value = nullptr;
132 if (argValue != nullptr)
133 {
134 // If argument is a CL object, fetch the mapped value
135 const CLContextCL &ctx = mKernel.getProgram().getContext().getImpl<CLContextCL>();
136 if (argSize == sizeof(cl_mem))
137 {
138 cl_mem memory = *static_cast<const cl_mem *>(argValue);
139 if (ctx.hasMemory(memory))
140 {
141 value = memory->cast<cl::Memory>().getImpl<CLMemoryCL>().getNative();
142 }
143 }
144 if (value == nullptr && argSize == sizeof(cl_sampler))
145 {
146 cl_sampler sampler = *static_cast<const cl_sampler *>(argValue);
147 if (ctx.hasSampler(sampler))
148 {
149 value = sampler->cast<cl::Sampler>().getImpl<CLSamplerCL>().getNative();
150 }
151 }
152 if (value == nullptr && argSize == sizeof(cl_command_queue))
153 {
154 cl_command_queue queue = *static_cast<const cl_command_queue *>(argValue);
155 if (ctx.hasDeviceQueue(queue))
156 {
157 value = queue->cast<cl::CommandQueue>().getImpl<CLCommandQueueCL>().getNative();
158 }
159 }
160 }
161
162 // If mapped value was found, use it instead of original value
163 if (value != nullptr)
164 {
165 argValue = &value;
166 }
167 return mNative->getDispatch().clSetKernelArg(mNative, argIndex, argSize, argValue);
168 }
169
createInfo(cl_int & errorCode) const170 CLKernelImpl::Info CLKernelCL::createInfo(cl_int &errorCode) const
171 {
172 const cl::Context &ctx = mKernel.getProgram().getContext();
173 Info info;
174
175 if (!GetKernelString(mNative, cl::KernelInfo::FunctionName, info.functionName, errorCode) ||
176 !GetKernelInfo(mNative, cl::KernelInfo::NumArgs, info.numArgs, errorCode) ||
177 (ctx.getPlatform().isVersionOrNewer(1u, 2u) &&
178 !GetKernelString(mNative, cl::KernelInfo::Attributes, info.attributes, errorCode)))
179 {
180 return Info{};
181 }
182
183 info.workGroups.resize(ctx.getDevices().size());
184 for (size_t index = 0u; index < ctx.getDevices().size(); ++index)
185 {
186 const cl_device_id device = ctx.getDevices()[index]->getImpl<CLDeviceCL>().getNative();
187 WorkGroupInfo &workGroup = info.workGroups[index];
188
189 if ((ctx.getPlatform().isVersionOrNewer(1u, 2u) &&
190 ctx.getDevices()[index]->supportsBuiltInKernel(info.functionName) &&
191 !GetWorkGroupInfo(mNative, device, cl::KernelWorkGroupInfo::GlobalWorkSize,
192 workGroup.globalWorkSize, errorCode)) ||
193 !GetWorkGroupInfo(mNative, device, cl::KernelWorkGroupInfo::WorkGroupSize,
194 workGroup.workGroupSize, errorCode) ||
195 !GetWorkGroupInfo(mNative, device, cl::KernelWorkGroupInfo::CompileWorkGroupSize,
196 workGroup.compileWorkGroupSize, errorCode) ||
197 !GetWorkGroupInfo(mNative, device, cl::KernelWorkGroupInfo::LocalMemSize,
198 workGroup.localMemSize, errorCode) ||
199 !GetWorkGroupInfo(mNative, device,
200 cl::KernelWorkGroupInfo::PreferredWorkGroupSizeMultiple,
201 workGroup.prefWorkGroupSizeMultiple, errorCode) ||
202 !GetWorkGroupInfo(mNative, device, cl::KernelWorkGroupInfo::PrivateMemSize,
203 workGroup.privateMemSize, errorCode))
204 {
205 return Info{};
206 }
207 }
208
209 info.args.resize(info.numArgs);
210 if (ctx.getPlatform().isVersionOrNewer(1u, 2u))
211 {
212 for (cl_uint index = 0u; index < info.numArgs; ++index)
213 {
214 ArgInfo &arg = info.args[index];
215 if (!GetArgInfo(mNative, index, cl::KernelArgInfo::AddressQualifier,
216 arg.addressQualifier, errorCode) ||
217 !GetArgInfo(mNative, index, cl::KernelArgInfo::AccessQualifier, arg.accessQualifier,
218 errorCode) ||
219 !GetArgString(mNative, index, cl::KernelArgInfo::TypeName, arg.typeName,
220 errorCode) ||
221 !GetArgInfo(mNative, index, cl::KernelArgInfo::TypeQualifier, arg.typeQualifier,
222 errorCode) ||
223 !GetArgString(mNative, index, cl::KernelArgInfo::Name, arg.name, errorCode))
224 {
225 return Info{};
226 }
227 }
228 }
229
230 return info;
231 }
232
233 } // namespace rx
234