Skip to content

Commit ee1a3bc

Browse files
committed
add enough support to pass conformance
1 parent d79c921 commit ee1a3bc

File tree

6 files changed

+560
-0
lines changed

6 files changed

+560
-0
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Copyright (c) 2025 Ben Ashbaugh
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
add_opencl_layer(
6+
NUMBER 21
7+
TARGET SGRotateEmu
8+
VERSION 300
9+
SOURCES main.cpp emulate.cpp emulate.h)

layers/21_sgrotateemu/emulate.cpp

Lines changed: 330 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,330 @@
1+
/*
2+
// Copyright (c) 2025 Ben Ashbaugh
3+
//
4+
// SPDX-License-Identifier: MIT
5+
*/
6+
7+
#include <CL/cl.h>
8+
#include <CL/cl_layer.h>
9+
10+
#include <algorithm>
11+
#include <array>
12+
#include <atomic>
13+
#include <map>
14+
#include <string>
15+
#include <vector>
16+
17+
#include "layer_util.hpp"
18+
19+
#include "emulate.h"
20+
#include "sgrotate.cl.h"
21+
22+
static constexpr cl_version version_cl_khr_subgroup_rotate =
23+
CL_MAKE_VERSION(1, 0, 0);
24+
25+
struct SDeviceInfo
26+
{
27+
bool supports_cl_khr_subgroup_rotate = true;
28+
};
29+
30+
struct SLayerContext
31+
{
32+
SLayerContext()
33+
{
34+
cl_uint numPlatforms = 0;
35+
g_pNextDispatch->clGetPlatformIDs(
36+
0,
37+
nullptr,
38+
&numPlatforms);
39+
40+
std::vector<cl_platform_id> platforms;
41+
platforms.resize(numPlatforms);
42+
g_pNextDispatch->clGetPlatformIDs(
43+
numPlatforms,
44+
platforms.data(),
45+
nullptr);
46+
47+
for (auto platform : platforms) {
48+
getDeviceInfoForPlatform(platform);
49+
}
50+
}
51+
52+
const SDeviceInfo& getDeviceInfo(cl_device_id device) const
53+
{
54+
// TODO: query the parent device if this is a sub-device?
55+
return m_DeviceInfo.at(device);
56+
}
57+
58+
const SDeviceInfo& getDeviceInfo(cl_device_id device)
59+
{
60+
// TODO: query the parent device if this is a sub-device?
61+
return m_DeviceInfo[device];
62+
}
63+
64+
private:
65+
std::map<cl_device_id, SDeviceInfo> m_DeviceInfo;
66+
67+
void getDeviceInfoForPlatform(cl_platform_id platform)
68+
{
69+
cl_uint numDevices = 0;
70+
g_pNextDispatch->clGetDeviceIDs(
71+
platform,
72+
CL_DEVICE_TYPE_ALL,
73+
0,
74+
nullptr,
75+
&numDevices);
76+
77+
std::vector<cl_device_id> devices;
78+
devices.resize(numDevices);
79+
g_pNextDispatch->clGetDeviceIDs(
80+
platform,
81+
CL_DEVICE_TYPE_ALL,
82+
numDevices,
83+
devices.data(),
84+
nullptr);
85+
86+
for (auto device : devices) {
87+
SDeviceInfo& deviceInfo = m_DeviceInfo[device];
88+
89+
size_t size = 0;
90+
91+
std::string deviceExtensions;
92+
g_pNextDispatch->clGetDeviceInfo(
93+
device,
94+
CL_DEVICE_EXTENSIONS,
95+
0,
96+
nullptr,
97+
&size);
98+
if (size) {
99+
deviceExtensions.resize(size);
100+
g_pNextDispatch->clGetDeviceInfo(
101+
device,
102+
CL_DEVICE_EXTENSIONS,
103+
size,
104+
&deviceExtensions[0],
105+
nullptr);
106+
deviceExtensions.pop_back();
107+
deviceInfo.supports_cl_khr_subgroup_rotate =
108+
checkStringForExtension(
109+
deviceExtensions.c_str(),
110+
CL_KHR_SUBGROUP_ROTATE_EXTENSION_NAME);
111+
}
112+
}
113+
}
114+
};
115+
116+
SLayerContext& getLayerContext(void)
117+
{
118+
static SLayerContext c;
119+
return c;
120+
}
121+
122+
static inline bool doEmulation(cl_device_id device)
123+
{
124+
const auto& deviceInfo = getLayerContext().getDeviceInfo(device);
125+
return !deviceInfo.supports_cl_khr_subgroup_rotate;
126+
}
127+
128+
static inline bool doEmulation(cl_context context)
129+
{
130+
cl_uint numDevices = 0;
131+
g_pNextDispatch->clGetContextInfo(
132+
context,
133+
CL_CONTEXT_NUM_DEVICES,
134+
sizeof(numDevices),
135+
&numDevices,
136+
nullptr);
137+
138+
std::vector<cl_device_id> devices(numDevices);
139+
g_pNextDispatch->clGetContextInfo(
140+
context,
141+
CL_CONTEXT_DEVICES,
142+
numDevices * sizeof(cl_device_id),
143+
devices.data(),
144+
nullptr);
145+
146+
return std::all_of(
147+
devices.begin(),
148+
devices.end(),
149+
[](cl_device_id device) { return doEmulation(device); });
150+
}
151+
152+
cl_program clCreateProgramWithSource_override(
153+
cl_context context,
154+
cl_uint count,
155+
const char** strings,
156+
const size_t* lengths,
157+
cl_int* errcode_ret)
158+
{
159+
if (!doEmulation(context)) {
160+
return g_pNextDispatch->clCreateProgramWithSource(
161+
context,
162+
count,
163+
strings,
164+
lengths,
165+
errcode_ret);
166+
}
167+
168+
if (count == 0 || strings == nullptr) {
169+
if (errcode_ret != nullptr) {
170+
*errcode_ret = CL_INVALID_VALUE;
171+
}
172+
return nullptr;
173+
}
174+
175+
std::vector<const char*> newStrings;
176+
newStrings.reserve(count + 1);
177+
newStrings.insert(newStrings.end(), g_SubgroupRotateString);
178+
newStrings.insert(newStrings.end(), strings, strings + count);
179+
180+
std::vector<size_t> newLengths;
181+
if (lengths != nullptr) {
182+
newLengths.reserve(count + 1);
183+
newLengths.insert(newLengths.end(), 0); // g_SubgroupRotateString is nul-terminated
184+
newLengths.insert(newLengths.end(), lengths, lengths + count);
185+
}
186+
187+
return g_pNextDispatch->clCreateProgramWithSource(
188+
context,
189+
count + 1,
190+
newStrings.data(),
191+
newLengths.size() ? newLengths.data() : nullptr,
192+
errcode_ret);
193+
}
194+
195+
196+
bool clGetDeviceInfo_override(
197+
cl_device_id device,
198+
cl_device_info param_name,
199+
size_t param_value_size,
200+
void* param_value,
201+
size_t* param_value_size_ret,
202+
cl_int* errcode_ret)
203+
{
204+
if (!doEmulation(device)) {
205+
return false;
206+
}
207+
208+
switch(param_name) {
209+
case CL_DEVICE_EXTENSIONS:
210+
{
211+
size_t size = 0;
212+
g_pNextDispatch->clGetDeviceInfo(
213+
device,
214+
CL_DEVICE_EXTENSIONS,
215+
0,
216+
nullptr,
217+
&size );
218+
219+
std::vector<char> deviceExtensions(size);
220+
g_pNextDispatch->clGetDeviceInfo(
221+
device,
222+
CL_DEVICE_EXTENSIONS,
223+
size,
224+
deviceExtensions.data(),
225+
nullptr );
226+
227+
if( checkStringForExtension(
228+
deviceExtensions.data(),
229+
CL_KHR_SUBGROUP_ROTATE_EXTENSION_NAME ) == false &&
230+
checkStringForExtension(
231+
deviceExtensions.data(),
232+
CL_KHR_SUBGROUP_SHUFFLE_EXTENSION_NAME ) )
233+
{
234+
std::string newExtensions;
235+
newExtensions += CL_KHR_SUBGROUP_ROTATE_EXTENSION_NAME;
236+
237+
std::string oldExtensions(deviceExtensions.data());
238+
239+
// If the old extension string ends with a space ensure the
240+
// new extension string does too.
241+
if( oldExtensions.back() == ' ' )
242+
{
243+
newExtensions += ' ';
244+
}
245+
else
246+
{
247+
oldExtensions += ' ';
248+
}
249+
250+
oldExtensions += newExtensions;
251+
252+
auto ptr = (char*)param_value;
253+
cl_int errorCode = writeStringToMemory(
254+
param_value_size,
255+
oldExtensions.c_str(),
256+
param_value_size_ret,
257+
ptr );
258+
259+
if( errcode_ret )
260+
{
261+
errcode_ret[0] = errorCode;
262+
}
263+
return true;
264+
}
265+
}
266+
break;
267+
case CL_DEVICE_EXTENSIONS_WITH_VERSION:
268+
{
269+
size_t size = 0;
270+
g_pNextDispatch->clGetDeviceInfo(
271+
device,
272+
CL_DEVICE_EXTENSIONS_WITH_VERSION,
273+
0,
274+
nullptr,
275+
&size );
276+
277+
size_t numExtensions = size / sizeof(cl_name_version);
278+
std::vector<cl_name_version> extensions(numExtensions);
279+
g_pNextDispatch->clGetDeviceInfo(
280+
device,
281+
CL_DEVICE_EXTENSIONS_WITH_VERSION,
282+
size,
283+
extensions.data(),
284+
nullptr );
285+
286+
bool supports_cl_khr_subgroup_rotate = false;
287+
bool supports_cl_khr_subgroup_shuffle = false;
288+
for( const auto& extension : extensions )
289+
{
290+
if( strcmp(extension.name, CL_KHR_SUBGROUP_ROTATE_EXTENSION_NAME) == 0 )
291+
{
292+
supports_cl_khr_subgroup_rotate = true;
293+
}
294+
if( strcmp(extension.name, CL_KHR_SUBGROUP_SHUFFLE_EXTENSION_NAME) == 0 )
295+
{
296+
supports_cl_khr_subgroup_shuffle = true;
297+
}
298+
}
299+
300+
if( supports_cl_khr_subgroup_rotate == false &&
301+
supports_cl_khr_subgroup_shuffle )
302+
{
303+
extensions.emplace_back();
304+
cl_name_version& extension = extensions.back();
305+
306+
memset(extension.name, 0, CL_NAME_VERSION_MAX_NAME_SIZE);
307+
strcpy(extension.name, CL_KHR_SUBGROUP_ROTATE_EXTENSION_NAME);
308+
309+
extension.version = version_cl_khr_subgroup_rotate;
310+
311+
auto ptr = (cl_name_version*)param_value;
312+
cl_int errorCode = writeVectorToMemory(
313+
param_value_size,
314+
extensions,
315+
param_value_size_ret,
316+
ptr );
317+
318+
if( errcode_ret )
319+
{
320+
errcode_ret[0] = errorCode;
321+
}
322+
return true;
323+
}
324+
}
325+
break;
326+
default: break;
327+
}
328+
329+
return false;
330+
}

layers/21_sgrotateemu/emulate.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
// Copyright (c) 2025 Ben Ashbaugh
3+
//
4+
// SPDX-License-Identifier: MIT
5+
*/
6+
7+
#include <CL/cl.h>
8+
#include <CL/cl_ext.h>
9+
10+
extern const struct _cl_icd_dispatch* g_pNextDispatch;
11+
12+
///////////////////////////////////////////////////////////////////////////////
13+
// Override Functions
14+
15+
cl_program clCreateProgramWithSource_override(
16+
cl_context context,
17+
cl_uint count,
18+
const char** strings,
19+
const size_t* lengths,
20+
cl_int* errcode_ret);
21+
22+
bool clGetDeviceInfo_override(
23+
cl_device_id device,
24+
cl_device_info param_name,
25+
size_t param_value_size,
26+
void* param_value,
27+
size_t* param_value_size_ret,
28+
cl_int* errcode_ret);

0 commit comments

Comments
 (0)