1 //
2 // Copyright (c) 2017 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 #ifndef TEST_CONFORMANCE_CLCPP_IMAGES_TEST_SAMPLE_HPP
17 #define TEST_CONFORMANCE_CLCPP_IMAGES_TEST_SAMPLE_HPP
18
19 #include <sstream>
20 #include <string>
21 #include <tuple>
22 #include <vector>
23
24 #include "common.hpp"
25
26
27 namespace test_images_sample {
28
29 enum class sampler_source
30 {
31 param,
32 program_scope
33 };
34
35 const sampler_source sampler_sources[] = { sampler_source::param, sampler_source::program_scope };
36
37 template<cl_mem_object_type ImageType, cl_channel_type ChannelType>
38 struct image_test : image_test_base<ImageType, ChannelType>
39 {
40 cl_channel_order channel_order;
41 sampler_source source;
42
image_testtest_images_sample::image_test43 image_test(cl_channel_order channel_order, sampler_source source) :
44 channel_order(channel_order),
45 source(source)
46 { }
47
48 // -----------------------------------------------------------------------------------
49 // ------------- ONLY FOR OPENCL 22 CONFORMANCE TEST 22 DEVELOPMENT ------------------
50 // -----------------------------------------------------------------------------------
51 #if defined(DEVELOPMENT) && defined(USE_OPENCLC_KERNELS)
generate_sourcetest_images_sample::image_test52 std::string generate_source()
53 {
54 std::stringstream s;
55 s << R"(
56 typedef )" << type_name<typename image_test::element_type>() << R"( element_type;
57 )";
58
59 std::string sampler;
60 if (source == sampler_source::program_scope)
61 {
62 s << R"(
63 constant sampler_t sampler_program_scope = CLK_FILTER_NEAREST | CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_NONE;
64 )";
65 sampler = "sampler_program_scope";
66 }
67 else if (source == sampler_source::param)
68 {
69 sampler = "sampler_param";
70 }
71
72 s << R"(
73 kernel void test(
74 read_only )" << image_test::image_type_name() << R"(_t img,
75 const global int4 *coords,
76 global element_type *output,
77 sampler_t sampler_param
78 ) {
79 const ulong gid = get_global_linear_id();
80
81 output[gid] = read_image)" << image_test::function_suffix() <<
82 "(img, " << sampler << ", coords[gid]." << image_test::coord_accessor() << R"();
83 }
84 )";
85
86 return s.str();
87 }
88 #else
generate_sourcetest_images_sample::image_test89 std::string generate_source()
90 {
91 std::stringstream s;
92 s << R"(
93 #include <opencl_memory>
94 #include <opencl_common>
95 #include <opencl_work_item>
96 #include <opencl_image>
97 using namespace cl;
98 )";
99
100 s << R"(
101 typedef )" << type_name<typename image_test::element_type>() << R"( element_type;
102 )";
103
104 std::string sampler;
105 if (source == sampler_source::program_scope)
106 {
107 s << R"(
108 sampler sampler_program_scope = make_sampler<addressing_mode::none, normalized_coordinates::unnormalized, filtering_mode::nearest>();
109 )";
110 sampler = "sampler_program_scope";
111 }
112 else if (source == sampler_source::param)
113 {
114 sampler = "sampler_param";
115 }
116
117 s << R"(
118 kernel void test(
119 const )" << image_test::image_type_name() << R"(<element_type, image_access::sample> img,
120 const global_ptr<int4[]> coords,
121 global_ptr<element_type[]> output,
122 sampler sampler_param
123 ) {
124 const ulong gid = get_global_linear_id();
125
126 output[gid] = img.sample()" << sampler << ", coords[gid]." << image_test::coord_accessor() << R"();
127 }
128 )";
129
130 return s.str();
131 }
132 #endif
133
runtest_images_sample::image_test134 int run(cl_device_id device, cl_context context, cl_command_queue queue, int num_elements)
135 {
136 int error = CL_SUCCESS;
137
138 cl_program program;
139 cl_kernel kernel;
140
141 std::string kernel_name = "test";
142 std::string source = generate_source();
143
144 // -----------------------------------------------------------------------------------
145 // ------------- ONLY FOR OPENCL 22 CONFORMANCE TEST 22 DEVELOPMENT ------------------
146 // -----------------------------------------------------------------------------------
147 // Only OpenCL C++ to SPIR-V compilation
148 #if defined(DEVELOPMENT) && defined(ONLY_SPIRV_COMPILATION)
149 error = create_opencl_kernel(
150 context, &program, &kernel,
151 source, kernel_name
152 );
153 RETURN_ON_ERROR(error)
154 return error;
155 // Use OpenCL C kernels instead of OpenCL C++ kernels (test C++ host code)
156 #elif defined(DEVELOPMENT) && defined(USE_OPENCLC_KERNELS)
157 error = create_opencl_kernel(
158 context, &program, &kernel,
159 source, kernel_name, "-cl-std=CL2.0", false
160 );
161 RETURN_ON_ERROR(error)
162 // Normal run
163 #else
164 error = create_opencl_kernel(
165 context, &program, &kernel,
166 source, kernel_name
167 );
168 RETURN_ON_ERROR(error)
169 #endif
170
171 using element_type = typename image_test::element_type;
172 using coord_type = cl_int4;
173 using scalar_element_type = typename scalar_type<element_type>::type;
174 using channel_type = typename image_test::channel_type;
175
176 cl_image_format image_format;
177 image_format.image_channel_order = channel_order;
178 image_format.image_channel_data_type = ChannelType;
179
180 const size_t pixel_size = get_pixel_size(&image_format);
181 const size_t channel_count = get_channel_order_channel_count(image_format.image_channel_order);
182
183 cl_image_desc image_desc;
184 image_desc.image_type = ImageType;
185 if (ImageType == CL_MEM_OBJECT_IMAGE1D)
186 {
187 image_desc.image_width = 2048;
188 image_desc.image_height = 1;
189 image_desc.image_depth = 1;
190 }
191 else if (ImageType == CL_MEM_OBJECT_IMAGE2D)
192 {
193 image_desc.image_width = 256;
194 image_desc.image_height = 256;
195 image_desc.image_depth = 1;
196 }
197 else if (ImageType == CL_MEM_OBJECT_IMAGE3D)
198 {
199 image_desc.image_width = 64;
200 image_desc.image_height = 64;
201 image_desc.image_depth = 64;
202 }
203 image_desc.image_array_size = 0;
204 image_desc.image_row_pitch = image_desc.image_width * pixel_size;
205 image_desc.image_slice_pitch = image_desc.image_row_pitch * image_desc.image_height;
206 image_desc.num_mip_levels = 0;
207 image_desc.num_samples = 0;
208 image_desc.mem_object = NULL;
209
210 image_descriptor image_info = create_image_descriptor(image_desc, &image_format);
211
212 std::vector<channel_type> image_values = generate_input(
213 image_desc.image_width * image_desc.image_height * image_desc.image_depth * channel_count,
214 image_test::channel_min(), image_test::channel_max(),
215 std::vector<channel_type>()
216 );
217
218 const size_t count = num_elements;
219
220 std::vector<coord_type> coords = generate_input(
221 count,
222 detail::make_value<coord_type>(0),
223 coord_type {
224 static_cast<cl_int>(image_desc.image_width - 1),
225 static_cast<cl_int>(image_desc.image_height - 1),
226 static_cast<cl_int>(image_desc.image_depth - 1),
227 0
228 },
229 std::vector<coord_type>()
230 );
231
232 cl_mem img = clCreateImage(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
233 &image_format, &image_desc, static_cast<void *>(image_values.data()), &error);
234 RETURN_ON_CL_ERROR(error, "clCreateImage")
235
236 cl_mem coords_buffer = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
237 sizeof(coord_type) * count, static_cast<void *>(coords.data()), &error);
238 RETURN_ON_CL_ERROR(error, "clCreateBuffer")
239
240 cl_mem output_buffer = clCreateBuffer(context, CL_MEM_READ_ONLY, sizeof(element_type) * count, NULL, &error);
241 RETURN_ON_CL_ERROR(error, "clCreateBuffer")
242
243 const cl_sampler_properties sampler_properties[] = {
244 CL_SAMPLER_NORMALIZED_COORDS, CL_FALSE,
245 CL_SAMPLER_ADDRESSING_MODE, CL_ADDRESS_NONE,
246 CL_SAMPLER_FILTER_MODE, CL_FILTER_NEAREST,
247 0
248 };
249 cl_sampler sampler = clCreateSamplerWithProperties(context, sampler_properties, &error);
250 RETURN_ON_CL_ERROR(error, "clCreateSamplerWithProperties")
251
252 error = clSetKernelArg(kernel, 0, sizeof(cl_mem), &img);
253 RETURN_ON_CL_ERROR(error, "clSetKernelArg")
254 error = clSetKernelArg(kernel, 1, sizeof(coords_buffer), &coords_buffer);
255 RETURN_ON_CL_ERROR(error, "clSetKernelArg")
256 error = clSetKernelArg(kernel, 2, sizeof(output_buffer), &output_buffer);
257 RETURN_ON_CL_ERROR(error, "clSetKernelArg")
258 error = clSetKernelArg(kernel, 3, sizeof(sampler), &sampler);
259 RETURN_ON_CL_ERROR(error, "clSetKernelArg")
260
261 const size_t global_size = count;
262 error = clEnqueueNDRangeKernel(queue, kernel, 1, NULL, &global_size, NULL, 0, NULL, NULL);
263 RETURN_ON_CL_ERROR(error, "clEnqueueNDRangeKernel")
264
265 std::vector<element_type> output(count);
266 error = clEnqueueReadBuffer(
267 queue, output_buffer, CL_TRUE,
268 0, sizeof(element_type) * count,
269 static_cast<void *>(output.data()),
270 0, NULL, NULL
271 );
272 RETURN_ON_CL_ERROR(error, "clEnqueueReadBuffer")
273
274 for (size_t i = 0; i < count; i++)
275 {
276 const coord_type c = coords[i];
277 const element_type result = output[i];
278
279 element_type expected;
280 read_image_pixel<scalar_element_type>(static_cast<void *>(image_values.data()), &image_info,
281 c.s[0], c.s[1], c.s[2],
282 expected.s);
283
284 if (!are_equal(result, expected))
285 {
286 RETURN_ON_ERROR_MSG(-1,
287 "Sampling from coordinates %s failed. Expected: %s, got: %s",
288 format_value(c).c_str(), format_value(expected).c_str(), format_value(result).c_str()
289 );
290 }
291 }
292
293 clReleaseMemObject(img);
294 clReleaseMemObject(coords_buffer);
295 clReleaseMemObject(output_buffer);
296 clReleaseSampler(sampler);
297 clReleaseKernel(kernel);
298 clReleaseProgram(program);
299 return error;
300 }
301 };
302
303 template<cl_mem_object_type ImageType>
run_test_cases(cl_device_id device,cl_context context,cl_command_queue queue,int num_elements)304 int run_test_cases(cl_device_id device, cl_context context, cl_command_queue queue, int num_elements)
305 {
306 if (!is_test_supported(device))
307 return CL_SUCCESS;
308
309 int error = CL_SUCCESS;
310
311 for (auto channel_order : get_channel_orders(device))
312 for (auto source : sampler_sources)
313 {
314 error = image_test<ImageType, CL_SIGNED_INT8>(channel_order, source)
315 .run(device, context, queue, num_elements);
316 RETURN_ON_ERROR(error)
317 error = image_test<ImageType, CL_SIGNED_INT16>(channel_order, source)
318 .run(device, context, queue, num_elements);
319 RETURN_ON_ERROR(error)
320 error = image_test<ImageType, CL_SIGNED_INT32>(channel_order, source)
321 .run(device, context, queue, num_elements);
322 RETURN_ON_ERROR(error)
323
324 error = image_test<ImageType, CL_UNSIGNED_INT8>(channel_order, source)
325 .run(device, context, queue, num_elements);
326 RETURN_ON_ERROR(error)
327 error = image_test<ImageType, CL_UNSIGNED_INT16>(channel_order, source)
328 .run(device, context, queue, num_elements);
329 RETURN_ON_ERROR(error)
330 error = image_test<ImageType, CL_UNSIGNED_INT32>(channel_order, source)
331 .run(device, context, queue, num_elements);
332 RETURN_ON_ERROR(error)
333
334 error = image_test<ImageType, CL_FLOAT>(channel_order, source)
335 .run(device, context, queue, num_elements);
336 RETURN_ON_ERROR(error)
337 }
338
339 return error;
340 }
341
342
AUTO_TEST_CASE(test_images_sample_1d)343 AUTO_TEST_CASE(test_images_sample_1d)
344 (cl_device_id device, cl_context context, cl_command_queue queue, int num_elements)
345 {
346 return run_test_cases<CL_MEM_OBJECT_IMAGE1D>(device, context, queue, num_elements);
347 }
348
AUTO_TEST_CASE(test_images_sample_2d)349 AUTO_TEST_CASE(test_images_sample_2d)
350 (cl_device_id device, cl_context context, cl_command_queue queue, int num_elements)
351 {
352 return run_test_cases<CL_MEM_OBJECT_IMAGE2D>(device, context, queue, num_elements);
353 }
354
AUTO_TEST_CASE(test_images_sample_3d)355 AUTO_TEST_CASE(test_images_sample_3d)
356 (cl_device_id device, cl_context context, cl_command_queue queue, int num_elements)
357 {
358 return run_test_cases<CL_MEM_OBJECT_IMAGE3D>(device, context, queue, num_elements);
359 }
360
361 } // namespace
362
363 #endif // TEST_CONFORMANCE_CLCPP_IMAGES_TEST_SAMPLE_HPP
364