1 //
2 // Copyright (c) 2022 The Khronos Group Inc.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 #include "basic_command_buffer.h"
17 #include "procs.h"
18
19 #include <vector>
20
21 namespace {
22
23 ////////////////////////////////////////////////////////////////////////////////
24 // Command-queue substitution tests which handles below cases:
25 // -substitution on queue without properties
26 // -substitution on queue with properties
27 // -simultaneous use queue substitution
28
29 template <bool prop_use, bool simul_use>
30 struct SubstituteQueueTest : public BasicCommandBufferTest
31 {
SubstituteQueueTest__anon33b54d660111::SubstituteQueueTest32 SubstituteQueueTest(cl_device_id device, cl_context context,
33 cl_command_queue queue)
34 : BasicCommandBufferTest(device, context, queue),
35 properties_use_requested(prop_use), user_event(nullptr)
36 {
37 simultaneous_use_requested = simul_use;
38 if (simul_use) buffer_size_multiplier = 2;
39 }
40
41 //--------------------------------------------------------------------------
Skip__anon33b54d660111::SubstituteQueueTest42 bool Skip() override
43 {
44 if (properties_use_requested)
45 {
46 Version version = get_device_cl_version(device);
47 const cl_device_info host_queue_query = version >= Version(2, 0)
48 ? CL_DEVICE_QUEUE_ON_HOST_PROPERTIES
49 : CL_DEVICE_QUEUE_PROPERTIES;
50
51 cl_queue_properties host_queue_props = 0;
52 int error = clGetDeviceInfo(device, host_queue_query,
53 sizeof(host_queue_props),
54 &host_queue_props, NULL);
55 test_error(error, "clGetDeviceInfo failed");
56
57 if ((host_queue_props & CL_QUEUE_PROFILING_ENABLE) == 0)
58 return true;
59 }
60
61 return BasicCommandBufferTest::Skip()
62 || (simultaneous_use_requested && !simultaneous_use_support);
63 }
64
65 //--------------------------------------------------------------------------
SetUp__anon33b54d660111::SubstituteQueueTest66 cl_int SetUp(int elements) override
67 {
68 // By default command queue is created without properties,
69 // if test requires queue with properties default queue must be
70 // replaced.
71 if (properties_use_requested)
72 {
73 // due to the skip condition
74 cl_int error = CL_SUCCESS;
75 queue = clCreateCommandQueue(context, device,
76 CL_QUEUE_PROFILING_ENABLE, &error);
77 test_error(
78 error,
79 "clCreateCommandQueue with CL_QUEUE_PROFILING_ENABLE failed");
80 }
81
82 return BasicCommandBufferTest::SetUp(elements);
83 }
84
85 //--------------------------------------------------------------------------
Run__anon33b54d660111::SubstituteQueueTest86 cl_int Run() override
87 {
88 // record command buffer with primary queue
89 cl_int error = RecordCommandBuffer();
90 test_error(error, "RecordCommandBuffer failed");
91
92 // create substitute queue
93 clCommandQueueWrapper new_queue;
94 if (properties_use_requested)
95 {
96 new_queue = clCreateCommandQueue(context, device,
97 CL_QUEUE_PROFILING_ENABLE, &error);
98 test_error(
99 error,
100 "clCreateCommandQueue with CL_QUEUE_PROFILING_ENABLE failed");
101 }
102 else
103 {
104 const cl_command_queue_properties queue_properties = 0;
105 new_queue =
106 clCreateCommandQueue(context, device, queue_properties, &error);
107 test_error(error, "clCreateCommandQueue failed");
108 }
109
110 if (simultaneous_use_support)
111 {
112 // enque simultaneous command-buffers with substitute queue
113 error = RunSimultaneous(new_queue);
114 test_error(error, "RunSimultaneous failed");
115 }
116 else
117 {
118 // enque single command-buffer with substitute queue
119 error = RunSingle(new_queue);
120 test_error(error, "RunSingle failed");
121 }
122
123 return CL_SUCCESS;
124 }
125
126 //--------------------------------------------------------------------------
RecordCommandBuffer__anon33b54d660111::SubstituteQueueTest127 cl_int RecordCommandBuffer()
128 {
129 cl_int error = clCommandNDRangeKernelKHR(
130 command_buffer, nullptr, nullptr, kernel, 1, nullptr, &num_elements,
131 nullptr, 0, nullptr, nullptr, nullptr);
132 test_error(error, "clCommandNDRangeKernelKHR failed");
133
134 error = clFinalizeCommandBufferKHR(command_buffer);
135 test_error(error, "clFinalizeCommandBufferKHR failed");
136 return CL_SUCCESS;
137 }
138
139 //--------------------------------------------------------------------------
RunSingle__anon33b54d660111::SubstituteQueueTest140 cl_int RunSingle(const cl_command_queue& q)
141 {
142 cl_int error = CL_SUCCESS;
143 std::vector<cl_int> output_data(num_elements);
144
145 error = clEnqueueFillBuffer(q, in_mem, &pattern_pri, sizeof(cl_int), 0,
146 data_size(), 0, nullptr, nullptr);
147 test_error(error, "clEnqueueFillBuffer failed");
148
149 cl_command_queue queues[] = { q };
150 error = clEnqueueCommandBufferKHR(1, queues, command_buffer, 0, nullptr,
151 nullptr);
152 test_error(error, "clEnqueueCommandBufferKHR failed");
153
154 error = clEnqueueReadBuffer(q, out_mem, CL_TRUE, 0, data_size(),
155 output_data.data(), 0, nullptr, nullptr);
156 test_error(error, "clEnqueueReadBuffer failed");
157
158 error = clFinish(q);
159 test_error(error, "clFinish failed");
160
161 for (size_t i = 0; i < num_elements; i++)
162 {
163 CHECK_VERIFICATION_ERROR(pattern_pri, output_data[i], i);
164 }
165
166 return CL_SUCCESS;
167 }
168
169 //--------------------------------------------------------------------------
170 struct SimulPassData
171 {
172 cl_int pattern;
173 cl_int offset;
174 cl_command_queue queue;
175 std::vector<cl_int> output_buffer;
176 };
177
178 //--------------------------------------------------------------------------
EnqueueSimultaneousPass__anon33b54d660111::SubstituteQueueTest179 cl_int EnqueueSimultaneousPass(SimulPassData& pd)
180 {
181 cl_int error = clEnqueueFillBuffer(
182 pd.queue, in_mem, &pd.pattern, sizeof(cl_int),
183 pd.offset * sizeof(cl_int), data_size(), 0, nullptr, nullptr);
184 test_error(error, "clEnqueueFillBuffer failed");
185
186 error =
187 clEnqueueFillBuffer(pd.queue, off_mem, &pd.offset, sizeof(cl_int),
188 0, sizeof(cl_int), 0, nullptr, nullptr);
189 test_error(error, "clEnqueueFillBuffer failed");
190
191 if (!user_event)
192 {
193 user_event = clCreateUserEvent(context, &error);
194 test_error(error, "clCreateUserEvent failed");
195 }
196
197 cl_command_queue queues[] = { pd.queue };
198 error = clEnqueueCommandBufferKHR(1, queues, command_buffer, 1,
199 &user_event, nullptr);
200 test_error(error, "clEnqueueCommandBufferKHR failed");
201
202 error = clEnqueueReadBuffer(
203 pd.queue, out_mem, CL_FALSE, pd.offset * sizeof(cl_int),
204 data_size(), pd.output_buffer.data(), 0, nullptr, nullptr);
205
206 test_error(error, "clEnqueueReadBuffer failed");
207
208 return CL_SUCCESS;
209 }
210
211 //--------------------------------------------------------------------------
RunSimultaneous__anon33b54d660111::SubstituteQueueTest212 cl_int RunSimultaneous(const cl_command_queue& q)
213 {
214 cl_int error = CL_SUCCESS;
215 cl_int offset = static_cast<cl_int>(num_elements);
216
217 std::vector<SimulPassData> simul_passes = {
218 { pattern_pri, 0, q, std::vector<cl_int>(num_elements) },
219 { pattern_sec, offset, q, std::vector<cl_int>(num_elements) }
220 };
221
222 for (auto&& pass : simul_passes)
223 {
224 error = EnqueueSimultaneousPass(pass);
225 test_error(error, "EnqueuePass failed");
226 }
227
228 error = clSetUserEventStatus(user_event, CL_COMPLETE);
229 test_error(error, "clSetUserEventStatus failed");
230
231 for (auto&& pass : simul_passes)
232 {
233 error = clFinish(pass.queue);
234 test_error(error, "clFinish failed");
235
236 auto& res_data = pass.output_buffer;
237
238 for (size_t i = 0; i < num_elements; i++)
239 {
240 CHECK_VERIFICATION_ERROR(pass.pattern, res_data[i], i);
241 }
242 }
243
244 return CL_SUCCESS;
245 }
246
247 //--------------------------------------------------------------------------
248 const cl_int pattern_pri = 0xB;
249 const cl_int pattern_sec = 0xC;
250
251 bool properties_use_requested;
252 clEventWrapper user_event;
253 };
254
255 } // anonymous namespace
256
test_queue_substitution(cl_device_id device,cl_context context,cl_command_queue queue,int num_elements)257 int test_queue_substitution(cl_device_id device, cl_context context,
258 cl_command_queue queue, int num_elements)
259 {
260 return MakeAndRunTest<SubstituteQueueTest<false, false>>(
261 device, context, queue, num_elements);
262 }
263
test_properties_queue_substitution(cl_device_id device,cl_context context,cl_command_queue queue,int num_elements)264 int test_properties_queue_substitution(cl_device_id device, cl_context context,
265 cl_command_queue queue, int num_elements)
266 {
267 return MakeAndRunTest<SubstituteQueueTest<true, false>>(
268 device, context, queue, num_elements);
269 }
270
test_simultaneous_queue_substitution(cl_device_id device,cl_context context,cl_command_queue queue,int num_elements)271 int test_simultaneous_queue_substitution(cl_device_id device,
272 cl_context context,
273 cl_command_queue queue,
274 int num_elements)
275 {
276 return MakeAndRunTest<SubstituteQueueTest<false, true>>(
277 device, context, queue, num_elements);
278 }
279