DPC++ Runtime
Runtime libraries for oneAPI DPC++
image_accessor_util.hpp
Go to the documentation of this file.
1 //==------------ image_accessor_util.hpp -----------------------------------==//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 // This file includes some utilities that are used by image accessors in host
9 // code
10 //
11 
12 #pragma once
13 
14 #ifndef __SYCL_DEVICE_ONLY__
15 
16 #include <sycl/aliases.hpp> // for float4, int4, uint4
17 #include <sycl/builtins.hpp> // for clamp, fmax, min
18 #include <sycl/detail/array.hpp> // for array
19 #include <sycl/detail/export.hpp> // for __SYCL_EXPORT
20 #include <sycl/detail/generic_type_traits.hpp> // for max_v, min_v, TryToGe...
21 #include <sycl/detail/type_list.hpp> // for is_contained, type_list
22 #include <sycl/exception.hpp>
23 #include <sycl/id.hpp> // for id
24 #include <sycl/image.hpp> // for image_channel_type
25 #include <sycl/range.hpp> // for range
26 #include <sycl/sampler.hpp> // for addressing_mode, coor...
27 #include <sycl/types.hpp> // for vec, operator*, round...
28 
29 #include <cstdint> // for int32_t, uint16_t
30 #include <stddef.h> // for size_t
31 #include <type_traits> // for enable_if_t
32 
33 namespace sycl {
34 inline namespace _V1 {
35 namespace detail {
36 
37 template <typename T>
38 using IsValidCoordType = typename is_contained<
39  T, boost::mp11::mp_unique<type_list<opencl::cl_int, opencl::cl_float,
40  std::int32_t, float>>>::type;
41 
42 // The formula for unnormalization coordinates:
43 // NormalizedCoords = [UnnormalizedCoords[i] * Range[i] for i in range(0, 3)]
44 template <typename T>
45 std::enable_if_t<IsValidCoordType<T>::value, T>
46 UnnormalizeCoordinates(const T &Coords, const range<3> &Range) {
47  return Coords * Range[0];
48 }
49 
50 template <typename T>
51 std::enable_if_t<IsValidCoordType<T>::value, vec<T, 2>>
52 UnnormalizeCoordinates(const vec<T, 2> &Coords, const range<3> &Range) {
53  return {Coords.x() * Range[0], Coords.y() * Range[1]};
54 }
55 
56 template <typename T>
57 std::enable_if_t<IsValidCoordType<T>::value, vec<T, 4>>
58 UnnormalizeCoordinates(const vec<T, 4> &Coords, const range<3> &Range) {
59  return {Coords.x() * Range[0], Coords.y() * Range[1], Coords.z() * Range[2],
60  0};
61 }
62 
63 // Converts the Coordinates from any dimensions into float4.
64 // valid but unused coordinates are written as 0.5 so the Int_uvwsubhalf
65 // calculation won't pass 0.
66 // Non-valid coordinates are written as 0.
67 template <typename T>
68 std::enable_if_t<IsValidCoordType<T>::value, float4> convertToFloat4(T Coords) {
69  return {static_cast<float>(Coords), 0.5f, 0.5f, 0.f};
70 }
71 
72 template <typename T>
73 std::enable_if_t<IsValidCoordType<T>::value, float4>
75  return {static_cast<float>(Coords.x()), static_cast<float>(Coords.y()), 0.5f,
76  0.f};
77 }
78 
79 template <typename T>
80 std::enable_if_t<IsValidCoordType<T>::value, float4>
82  return {static_cast<float>(Coords.x()), static_cast<float>(Coords.y()),
83  static_cast<float>(Coords.z()), 0.f};
84 }
85 
86 // This method compute an offset in bytes for a given Coords.
87 // Retured offset is used to find the address location of a pixel from a base
88 // ptr.
89 template <typename T>
90 std::enable_if_t<std::is_integral_v<T>, size_t>
91 getImageOffset(const T &Coords, const id<3>, const uint8_t ElementSize) {
92  return Coords * ElementSize;
93 }
94 
95 template <typename T>
96 std::enable_if_t<std::is_integral_v<T>, size_t>
97 getImageOffset(const vec<T, 2> &Coords, const id<3> ImgPitch,
98  const uint8_t ElementSize) {
99  return Coords.x() * ElementSize + Coords.y() * ImgPitch[0];
100 }
101 
102 template <typename T>
103 std::enable_if_t<std::is_integral_v<T>, size_t>
104 getImageOffset(const vec<T, 4> &Coords, const id<3> ImgPitch,
105  const uint8_t ElementSize) {
106  return Coords.x() * ElementSize + Coords.y() * ImgPitch[0] +
107  Coords.z() * ImgPitch[1];
108 }
109 
110 // Process float4 Coordinates and return the appropriate Pixel
111 // Coordinates to read from based on Addressing Mode for Nearest filter mode.
112 __SYCL_EXPORT int4 getPixelCoordNearestFiltMode(float4, const addressing_mode,
113  const range<3>);
114 
115 // Process float4 Coordinates and return the appropriate Pixel
116 // Coordinates to read from based on Addressing Mode for Linear filter mode.
117 __SYCL_EXPORT int8 getPixelCoordLinearFiltMode(float4, const addressing_mode,
118  const range<3>, float4 &);
119 
120 // Check if PixelCoord are out of range for Sampler with clamp adressing mode.
121 __SYCL_EXPORT bool isOutOfRange(const int4 PixelCoord,
122  const addressing_mode SmplAddrMode,
123  const range<3> ImgRange);
124 
125 // Get Border Color for the image_channel_order, the border color values are
126 // only used when the sampler has clamp addressing mode.
127 __SYCL_EXPORT float4 getBorderColor(const image_channel_order ImgChannelOrder);
128 
129 // Reads data from a pixel at Ptr location, based on the number of Channels in
130 // Order and returns the data.
131 // The datatype used to read from the Ptr is based on the T of the
132 // image. This datatype is computed by the calling API.
133 template <typename T>
134 vec<T, 4> readPixel(T *Ptr, const image_channel_order ChannelOrder,
135  const image_channel_type ChannelType) {
136  vec<T, 4> Pixel(0);
137 
138  switch (ChannelOrder) {
140  Pixel.w() = Ptr[0];
141  break;
144  Pixel.x() = Ptr[0];
145  Pixel.w() = 1;
146  break;
148  Pixel.x() = Ptr[0];
149  Pixel.y() = Ptr[0];
150  Pixel.z() = Ptr[0];
151  Pixel.w() = Ptr[0];
152  break;
154  Pixel.x() = Ptr[0];
155  Pixel.y() = Ptr[0];
156  Pixel.z() = Ptr[0];
157  Pixel.w() = 1.0;
158  break;
161  Pixel.x() = Ptr[0];
162  Pixel.y() = Ptr[1];
163  Pixel.w() = 1.0;
164  break;
166  Pixel.x() = Ptr[0];
167  Pixel.w() = Ptr[1];
168  break;
171  if (ChannelType == image_channel_type::unorm_short_565 ||
172  ChannelType == image_channel_type::unorm_short_555 ||
173  ChannelType == image_channel_type::unorm_int_101010) {
174  Pixel.x() = Ptr[0];
175  } else {
176  Pixel.x() = Ptr[0];
177  Pixel.y() = Ptr[1];
178  Pixel.z() = Ptr[2];
179  Pixel.w() = 1.0;
180  }
181  break;
184  Pixel.x() = Ptr[0]; // r
185  Pixel.y() = Ptr[1]; // g
186  Pixel.z() = Ptr[2]; // b
187  Pixel.w() = Ptr[3]; // a
188  break;
190  Pixel.w() = Ptr[0]; // a
191  Pixel.x() = Ptr[1]; // r
192  Pixel.y() = Ptr[2]; // g
193  Pixel.z() = Ptr[3]; // b
194  break;
196  Pixel.z() = Ptr[0]; // b
197  Pixel.y() = Ptr[1]; // g
198  Pixel.x() = Ptr[2]; // r
199  Pixel.w() = Ptr[3]; // a
200  break;
202  Pixel.w() = Ptr[0]; // a
203  Pixel.z() = Ptr[1]; // b
204  Pixel.y() = Ptr[2]; // g
205  Pixel.x() = Ptr[3]; // r
206  break;
207  }
208 
209  return Pixel;
210 }
211 
212 // Write data to a pixel at Ptr location, based on the number of Channels in
213 // ImageChannelOrder. The data passed to this API in 'Pixel' is already
214 // converted to Datatype of the Channel based on ImageChannelType by the calling
215 // API.
216 template <typename T>
217 void writePixel(const vec<T, 4> Pixel, T *Ptr,
218  const image_channel_order ChannelOrder,
219  const image_channel_type ChannelType) {
220 
221  // Data is written based on section 6.12.14.6 of openCL spec.
222  switch (ChannelOrder) {
224  Ptr[0] = Pixel.w();
225  break;
230  Ptr[0] = Pixel.x();
231  break;
234  Ptr[0] = Pixel.x();
235  Ptr[1] = Pixel.y();
236  break;
238  Ptr[0] = Pixel.x();
239  Ptr[1] = Pixel.w();
240  break;
243  if (ChannelType == image_channel_type::unorm_short_565 ||
244  ChannelType == image_channel_type::unorm_short_555 ||
245  ChannelType == image_channel_type::unorm_int_101010) {
246  Ptr[0] = Pixel.x();
247  } else {
248  Ptr[0] = Pixel.x();
249  Ptr[1] = Pixel.y();
250  Ptr[2] = Pixel.z();
251  }
252  break;
255  Ptr[0] = Pixel.x(); // r
256  Ptr[1] = Pixel.y(); // g
257  Ptr[2] = Pixel.z(); // b
258  Ptr[3] = Pixel.w(); // a
259  break;
261  Ptr[0] = Pixel.w(); // a
262  Ptr[1] = Pixel.x(); // r
263  Ptr[2] = Pixel.y(); // g
264  Ptr[3] = Pixel.z(); // b
265  break;
267  Ptr[0] = Pixel.z(); // b
268  Ptr[1] = Pixel.y(); // g
269  Ptr[2] = Pixel.x(); // r
270  Ptr[3] = Pixel.w(); // a
271  break;
273  Ptr[0] = Pixel.w(); // a
274  Ptr[1] = Pixel.z(); // b
275  Ptr[2] = Pixel.y(); // g
276  Ptr[3] = Pixel.x(); // r
277  break;
278  }
279 }
280 
281 // Converts read pixel data into return datatype based on the channel type of
282 // the image.
283 // Conversion rules used as given in the OpenCL
284 // Spec section 8.3. The conversion rules may be handled differently for each
285 // return datatype - float, int32, uint32, half. ImageChannelType is passed to
286 // the function to use appropriate conversion rules.
287 
288 template <typename ChannelType>
290  const image_channel_type ImageChannelType,
291  uint4 &RetData) {
292 
293  switch (ImageChannelType) {
297  RetData = PixelData.template convert<std::uint32_t>();
298  break;
299  default:
300  // OpenCL Spec section 6.12.14.2 does not allow reading uint4 data from an
301  // image with channel datatype other than unsigned_int8,unsigned_int16 and
302  // unsigned_int32.
304  "Datatype of read data - cl_uint4 is incompatible "
305  "with the image_channel_type of the image.");
306  }
307 }
308 
309 template <typename ChannelType>
311  const image_channel_type ImageChannelType, int4 &RetData) {
312 
313  switch (ImageChannelType) {
317  RetData = PixelData.template convert<std::int32_t>();
318  break;
319  default:
320  // OpenCL Spec section 6.12.14.2 does not allow reading int4 data from an
321  // image with channel datatype other than signed_int8,signed_int16 and
322  // signed_int32.
324  "Datatype of read data - cl_int4 is incompatible "
325  "with the image_channel_type of the image.");
326  }
327 }
328 
329 template <typename ChannelType>
331  const image_channel_type ImageChannelType,
332  float4 &RetData) {
333 
334  switch (ImageChannelType) {
336  // max(-1.0f, (float)c / 127.0f)
337  RetData = (PixelData.template convert<float>()) / 127.0f;
338  RetData = sycl::fmax(RetData, -1);
339  break;
341  // max(-1.0f, (float)c / 32767.0f)
342  RetData = (PixelData.template convert<float>()) / 32767.0f;
343  RetData = sycl::fmax(RetData, -1);
344  break;
346  // (float)c / 255.0f
347  RetData = (PixelData.template convert<float>()) / 255.0f;
348  break;
350  // (float)c / 65535.0f
351  RetData = (PixelData.template convert<float>()) / 65535.0f;
352  break;
354  // TODO: Missing information in OpenCL spec. check if the below code is
355  // correct after the spec is updated.
356  // Assuming: (float)c / 31.0f; c represents the 5-bit integer.
357  // (float)c / 63.0f; c represents the 6-bit integer.
358  // PixelData.x will be of type std::uint16_t.
359  ushort4 Temp(PixelData.x());
360  ushort4 MaskBits(0xF800 /*r:bits 11-15*/, 0x07E0 /*g:bits 5-10*/,
361  0x001F /*b:bits 0-4*/, 0x0000);
362  ushort4 ShiftBits(11, 5, 0, 0);
363  float4 DivisorToNormalise(31.0f, 63.0f, 31.0f, 1);
364  Temp = (Temp & MaskBits) >> ShiftBits;
365  RetData = (Temp.template convert<float>()) / DivisorToNormalise;
366  break;
367  }
369  // TODO: Missing information in OpenCL spec. check if the below code is
370  // correct after the spec is updated.
371  // Assuming: (float)c / 31.0f; c represents the 5-bit integer.
372 
373  // Extracting each 5-bit channel data.
374  // PixelData.x will be of type std::uint16_t.
375  ushort4 Temp(PixelData.x());
376  ushort4 MaskBits(0x7C00 /*r:bits 10-14*/, 0x03E0 /*g:bits 5-9*/,
377  0x001F /*b:bits 0-4*/, 0x0000);
378  ushort4 ShiftBits(10, 5, 0, 0);
379  Temp = (Temp & MaskBits) >> ShiftBits;
380  RetData = (Temp.template convert<float>()) / 31.0f;
381  break;
382  }
384  // Extracting each 10-bit channel data.
385  // PixelData.x will be of type std::uint32_t.
386  uint4 Temp(PixelData.x());
387  uint4 MaskBits(0x3FF00000 /*r:bits 20-29*/, 0x000FFC00 /*g:bits 10-19*/,
388  0x000003FF /*b:bits 0-9*/, 0x00000000);
389  uint4 ShiftBits(20, 10, 0, 0);
390  Temp = (Temp & MaskBits) >> ShiftBits;
391  RetData = (Temp.template convert<float>()) / 1023.0f;
392  break;
393  }
400  // OpenCL Spec section 6.12.14.2 does not allow reading float4 data from an
401  // image with channel datatype - signed/unsigned_int8,signed/unsigned_int16
402  // and signed/unsigned_int32.
404  "Datatype of read data - cl_float4 is incompatible "
405  "with the image_channel_type of the image.");
407  // Host has conversion from float to half with accuracy as required in
408  // section 8.3.2 OpenCL spec.
409  RetData = PixelData.template convert<float>();
410  break;
412  RetData = PixelData.template convert<float>();
413  break;
414  }
415 }
416 
417 template <typename ChannelType>
419  const image_channel_type ImageChannelType,
420  half4 &RetData) {
421  float4 RetDataFloat;
422  switch (ImageChannelType) {
424  // max(-1.0f, (half)c / 127.0f)
425  RetDataFloat = (PixelData.template convert<float>()) / 127.0f;
426  RetDataFloat = sycl::fmax(RetDataFloat, -1);
427  break;
429  // max(-1.0f, (half)c / 32767.0f)
430  RetDataFloat = (PixelData.template convert<float>()) / 32767.0f;
431  RetDataFloat = sycl::fmax(RetDataFloat, -1);
432  break;
434  // (half)c / 255.0f
435  RetDataFloat = (PixelData.template convert<float>()) / 255.0f;
436  break;
438  // (half)c / 65535.0f
439  RetDataFloat = (PixelData.template convert<float>()) / 65535.0f;
440  break;
444  // TODO: Missing information in OpenCL spec.
446  "Currently unsupported datatype conversion from "
447  "image_channel_type to cl_half4.");
454  // OpenCL Spec section 6.12.14.2 does not allow reading float4 data to an
455  // image with channel datatype - signed/unsigned_int8,signed/unsigned_int16
456  // and signed/unsigned_int32.
458  "Datatype to read- cl_half4 is incompatible with the "
459  "image_channel_type of the image.");
461  RetData = PixelData.template convert<half>();
462  return;
465  "Datatype to read - cl_half4 is incompatible with "
466  "the image_channel_type of the image.");
467  }
468  RetData = RetDataFloat.template convert<half>();
469 }
470 
471 // Converts data to write into appropriate datatype based on the channel of the
472 // image.
473 // The conversion rules used are as given in OpenCL Spec Section 8.3. The
474 // conversion rules are different for each return datatype - float,
475 // int32, uint32, half. ImageChannelType is passed to the function to use
476 // appropriate conversion rules.
477 template <typename ChannelType>
479 convertWriteData(const uint4 WriteData,
480  const image_channel_type ImageChannelType) {
481  switch (ImageChannelType) {
483  // convert_uchar_sat(Data)
484  std::uint32_t MinVal = min_v<std::uint8_t>();
485  std::uint32_t MaxVal = max_v<std::uint8_t>();
486  uint4 PixelData = sycl::clamp(WriteData, MinVal, MaxVal);
487  return PixelData.convert<ChannelType>();
488  }
490  // convert_ushort_sat(Data)
491  std::uint32_t MinVal = min_v<std::uint16_t>();
492  std::uint32_t MaxVal = max_v<std::uint16_t>();
493  uint4 PixelData = sycl::clamp(WriteData, MinVal, MaxVal);
494  return PixelData.convert<ChannelType>();
495  }
497  // no conversion is performed.
498  return WriteData.convert<ChannelType>();
499  default:
500  // OpenCL Spec section 6.12.14.4 does not allow writing uint4 data to an
501  // image with channel datatype other than unsigned_int8,unsigned_int16 and
502  // unsigned_int32.
503  throw sycl::exception(
505  "Datatype of data to write - cl_uint4 is incompatible with the "
506  "image_channel_type of the image.");
507  }
508 }
509 
510 template <typename ChannelType>
512 convertWriteData(const int4 WriteData,
513  const image_channel_type ImageChannelType) {
514 
515  switch (ImageChannelType) {
517  // convert_char_sat(Data)
518  std::int32_t MinVal = min_v<std::int8_t>();
519  std::int32_t MaxVal = max_v<std::int8_t>();
520  int4 PixelData = sycl::clamp(WriteData, MinVal, MaxVal);
521  return PixelData.convert<ChannelType>();
522  }
524  // convert_short_sat(Data)
525  std::int32_t MinVal = min_v<std::int16_t>();
526  std::int32_t MaxVal = max_v<std::int16_t>();
527  int4 PixelData = sycl::clamp(WriteData, MinVal, MaxVal);
528  return PixelData.convert<ChannelType>();
529  }
531  return WriteData.convert<ChannelType>();
532  default:
533  // OpenCL Spec section 6.12.14.4 does not allow writing int4 data to an
534  // image with channel datatype other than signed_int8,signed_int16 and
535  // signed_int32.
537  "Datatype of data to write - cl_int4 is incompatible "
538  "with the image_channel_type of the image.");
539  }
540 }
541 
542 template <typename ChannelType>
543 vec<ChannelType, 4> processFloatDataToPixel(float4 WriteData, float MulFactor) {
544  float4 Temp = WriteData * MulFactor;
545  int4 TempInInt = Temp.convert<int, rounding_mode::rte>();
546  int4 TempInIntSaturated =
547  sycl::clamp(TempInInt, min_v<ChannelType>(), max_v<ChannelType>());
548  return TempInIntSaturated.convert<ChannelType>();
549 }
550 
551 template <typename ChannelType>
553 convertWriteData(const float4 WriteData,
554  const image_channel_type ImageChannelType) {
555 
556  vec<ChannelType, 4> PixelData;
557 
558  switch (ImageChannelType) {
560  // convert_char_sat_rte(f * 127.0f)
561  return processFloatDataToPixel<ChannelType>(WriteData, 127.0f);
563  // convert_short_sat_rte(f * 32767.0f)
564  return processFloatDataToPixel<ChannelType>(WriteData, 32767.0f);
566  // convert_uchar_sat_rte(f * 255.0f)
567  return processFloatDataToPixel<ChannelType>(WriteData, 255.0f);
569  // convert_ushort_sat_rte(f * 65535.0f)
570  return processFloatDataToPixel<ChannelType>(WriteData, 65535.0f);
572  // TODO: Missing information in OpenCL spec.
574  "Currently unsupported datatype conversion from "
575  "image_channel_type to cl_float4.");
577  // TODO: Missing information in OpenCL spec.
578  // Check if the below code is correct after the spec is updated.
579  // Assuming: min(convert_ushort_sat_rte(f * 32.0f), 0x1f)
580  // bits 9:5 and B in bits 4:0.
581  {
582  ushort4 PixelData =
583  processFloatDataToPixel<std::uint16_t>(WriteData, 32.0f);
584  PixelData = sycl::min(PixelData, static_cast<ChannelType>(0x1f));
585  // Compressing the data into the first element of PixelData.
586  // This is needed so that the data can be directly stored into the pixel
587  // location from the first element.
588  // For CL_UNORM_SHORT_555, bit 15 is undefined, R is in bits 14:10, G
589  // in bits 9:5 and B in bits 4:0
590  PixelData.x() =
591  (PixelData.x() << 10) | (PixelData.y() << 5) | PixelData.z();
592  return PixelData.convert<ChannelType>();
593  }
595  // min(convert_ushort_sat_rte(f * 1023.0f), 0x3ff)
596  // For CL_UNORM_INT_101010, bits 31:30 are undefined, R is in bits 29:20, G
597  // in bits 19:10 and B in bits 9:0
598  {
599  uint4 PixelData =
600  processFloatDataToPixel<std::uint32_t>(WriteData, 1023.0f);
601  PixelData = sycl::min(PixelData, static_cast<ChannelType>(0x3ff));
602  PixelData.x() =
603  (PixelData.x() << 20) | (PixelData.y() << 10) | PixelData.z();
604  return PixelData.convert<ChannelType>();
605  }
612  // OpenCL Spec section 6.12.14.4 does not allow writing float4 data to an
613  // image with channel datatype - signed/unsigned_int8,signed/unsigned_int16
614  // and signed/unsigned_int32.
615  throw sycl::exception(
617  "Datatype of data to write - cl_float4 is incompatible with the "
618  "image_channel_type of the image.");
620  // Host has conversion from float to half with accuracy as required in
621  // section 8.3.2 OpenCL spec.
622  return WriteData.convert<ChannelType>();
624  return WriteData.convert<ChannelType>();
625  }
626 }
627 
628 template <typename ChannelType>
630 convertWriteData(const half4 WriteData,
631  const image_channel_type ImageChannelType) {
632  float4 WriteDataFloat = WriteData.convert<float>();
633  switch (ImageChannelType) {
635  // convert_char_sat_rte(h * 127.0f)
636  return processFloatDataToPixel<ChannelType>(WriteDataFloat, 127.0f);
638  // convert_short_sat_rte(h * 32767.0f)
639  return processFloatDataToPixel<ChannelType>(WriteDataFloat, 32767.0f);
641  // convert_uchar_sat_rte(h * 255.0f)
642  return processFloatDataToPixel<ChannelType>(WriteDataFloat, 255.0f);
644  // convert_ushort_sat_rte(h * 65535.0f)
645  return processFloatDataToPixel<ChannelType>(WriteDataFloat, 65535.0f);
649  // TODO: Missing information in OpenCL spec.
651  "Currently unsupported datatype conversion from "
652  "image_channel_type to cl_half4.");
659  // OpenCL Spec section 6.12.14.4 does not allow writing float4 data to an
660  // image with channel datatype - signed/unsigned_int8,signed/unsigned_int16
661  // and signed/unsigned_int32.
662  throw sycl::exception(
664  "Datatype of data to write - cl_float4 is incompatible with the "
665  "image_channel_type of the image.");
667  return WriteData.convert<ChannelType>();
669  throw sycl::exception(
671  "Datatype of data to write - cl_float4 is incompatible with the "
672  "image_channel_type of the image.");
673  }
674 }
675 
676 // imageWriteHostImpl method is called by the write API in image accessors for
677 // host code. Steps:
678 // 1. Calculates the offset from the base ptr of the image where the pixel
679 // denoted by Coord is located.(getImageOffset method.)
680 // 2. Converts the ptr to the appropriate datatype based on
681 // ImageChannelType.(reinterpret_cast)
682 // 3. The data is converted to the image pixel data based on conversion rules in
683 // the spec.(convertWriteData)
684 // 4. The converted data is then written to the pixel at Ptr, based on Number of
685 // Channels in the Image.(writePixel)
686 // Note: We assume that Coords are in the appropriate image range. OpenCL
687 // Spec says that the behaviour is undefined when the Coords are passed outside
688 // the image range. In the current implementation, the data gets written to the
689 // calculated Ptr.
690 template <typename CoordT, typename WriteDataT>
691 void imageWriteHostImpl(const CoordT &Coords, const WriteDataT &Color,
692  id<3> ImgPitch, uint8_t ElementSize,
693  image_channel_type ImgChannelType,
694  image_channel_order ImgChannelOrder, void *BasePtr) {
695  // Calculate position to write
696  auto Ptr = static_cast<unsigned char *>(BasePtr) +
697  getImageOffset(Coords, ImgPitch, ElementSize);
698 
699  switch (ImgChannelType) {
701  writePixel(convertWriteData<std::int8_t>(Color, ImgChannelType),
702  reinterpret_cast<std::int8_t *>(Ptr), ImgChannelOrder,
703  ImgChannelType);
704  break;
706  writePixel(convertWriteData<std::int16_t>(Color, ImgChannelType),
707  reinterpret_cast<std::int16_t *>(Ptr), ImgChannelOrder,
708  ImgChannelType);
709  break;
711  writePixel(convertWriteData<std::uint8_t>(Color, ImgChannelType),
712  reinterpret_cast<std::uint8_t *>(Ptr), ImgChannelOrder,
713  ImgChannelType);
714  break;
716  writePixel(convertWriteData<std::uint16_t>(Color, ImgChannelType),
717  reinterpret_cast<std::uint16_t *>(Ptr), ImgChannelOrder,
718  ImgChannelType);
719  break;
721  writePixel(convertWriteData<short>(Color, ImgChannelType),
722  reinterpret_cast<short *>(Ptr), ImgChannelOrder, ImgChannelType);
723  break;
725  writePixel(convertWriteData<short>(Color, ImgChannelType),
726  reinterpret_cast<short *>(Ptr), ImgChannelOrder, ImgChannelType);
727  break;
729  writePixel(convertWriteData<std::uint32_t>(Color, ImgChannelType),
730  reinterpret_cast<std::uint32_t *>(Ptr), ImgChannelOrder,
731  ImgChannelType);
732  break;
734  writePixel(convertWriteData<std::int8_t>(Color, ImgChannelType),
735  reinterpret_cast<std::int8_t *>(Ptr), ImgChannelOrder,
736  ImgChannelType);
737  break;
739  writePixel(convertWriteData<std::int16_t>(Color, ImgChannelType),
740  reinterpret_cast<std::int16_t *>(Ptr), ImgChannelOrder,
741  ImgChannelType);
742  break;
744  writePixel(convertWriteData<std::int32_t>(Color, ImgChannelType),
745  reinterpret_cast<std::int32_t *>(Ptr), ImgChannelOrder,
746  ImgChannelType);
747  break;
749  writePixel(convertWriteData<std::uint8_t>(Color, ImgChannelType),
750  reinterpret_cast<std::uint8_t *>(Ptr), ImgChannelOrder,
751  ImgChannelType);
752  break;
754  writePixel(convertWriteData<std::uint16_t>(Color, ImgChannelType),
755  reinterpret_cast<std::uint16_t *>(Ptr), ImgChannelOrder,
756  ImgChannelType);
757  break;
759  writePixel(convertWriteData<std::uint32_t>(Color, ImgChannelType),
760  reinterpret_cast<std::uint32_t *>(Ptr), ImgChannelOrder,
761  ImgChannelType);
762  break;
764  writePixel(convertWriteData<half>(Color, ImgChannelType),
765  reinterpret_cast<half *>(Ptr), ImgChannelOrder, ImgChannelType);
766  break;
768  writePixel(convertWriteData<float>(Color, ImgChannelType),
769  reinterpret_cast<float *>(Ptr), ImgChannelOrder, ImgChannelType);
770  break;
771  }
772 }
773 
774 // Method called to read a Coord by getColor function when the Coord is
775 // in-range. This method takes Unnormalized Coords - 'PixelCoord' as int4.
776 // Invalid Coord are denoted by 0. Steps:
777 // 1. Compute Offset for given Unnormalised Coordinates using ImagePitch and
778 // ElementSize.(getImageOffset)
779 // 2. Add this Offset to BasePtr to compute the location of the Image.
780 // 3. Convert this Ptr to the appropriate datatype pointer based on
781 // ImageChannelType. (reinterpret_cast)
782 // 4. Read the appropriate number of channels(computed using
783 // ImageChannelOrder) of the appropriate Channel datatype into Color
784 // variable.(readPixel)
785 // 5. Convert the Read Data into Return DataT based on conversion rules in
786 // the Spec.(convertReadData)
787 // Possible DataT are int4, uint4, float4, half4;
788 template <typename DataT>
789 DataT ReadPixelData(const int4 PixelCoord, const id<3> ImgPitch,
790  const image_channel_type ImageChannelType,
791  const image_channel_order ImageChannelOrder, void *BasePtr,
792  const uint8_t ElementSize) {
793  DataT Color(0);
794  auto Ptr = static_cast<unsigned char *>(BasePtr) +
795  getImageOffset(PixelCoord, ImgPitch,
796  ElementSize); // Utility to compute offset in
797  // image_accessor_util.hpp
798 
799  switch (ImageChannelType) {
800  // TODO: Pass either ImageChannelType or the exact channel type to the
801  // readPixel Function.
803  convertReadData<std::int8_t>(readPixel(reinterpret_cast<std::int8_t *>(Ptr),
804  ImageChannelOrder, ImageChannelType),
806  break;
808  convertReadData<std::int16_t>(
809  readPixel(reinterpret_cast<std::int16_t *>(Ptr), ImageChannelOrder,
810  ImageChannelType),
812  break;
814  convertReadData<std::uint8_t>(
815  readPixel(reinterpret_cast<std::uint8_t *>(Ptr), ImageChannelOrder,
816  ImageChannelType),
818  break;
820  convertReadData<std::uint16_t>(
821  readPixel(reinterpret_cast<std::uint16_t *>(Ptr), ImageChannelOrder,
822  ImageChannelType),
824  break;
826  convertReadData<std::uint16_t>(
827  readPixel(reinterpret_cast<std::uint16_t *>(Ptr), ImageChannelOrder,
828  ImageChannelType),
830  break;
832  convertReadData<std::uint16_t>(
833  readPixel(reinterpret_cast<std::uint16_t *>(Ptr), ImageChannelOrder,
834  ImageChannelType),
836  break;
838  convertReadData<std::uint32_t>(
839  readPixel(reinterpret_cast<std::uint32_t *>(Ptr), ImageChannelOrder,
840  ImageChannelType),
842  break;
844  convertReadData<std::int8_t>(readPixel(reinterpret_cast<std::int8_t *>(Ptr),
845  ImageChannelOrder, ImageChannelType),
847  break;
849  convertReadData<std::int16_t>(
850  readPixel(reinterpret_cast<std::int16_t *>(Ptr), ImageChannelOrder,
851  ImageChannelType),
853  break;
855  convertReadData<std::int32_t>(
856  readPixel(reinterpret_cast<std::int32_t *>(Ptr), ImageChannelOrder,
857  ImageChannelType),
859  break;
861  convertReadData<std::uint8_t>(
862  readPixel(reinterpret_cast<std::uint8_t *>(Ptr), ImageChannelOrder,
863  ImageChannelType),
865  break;
867  convertReadData<std::uint16_t>(
868  readPixel(reinterpret_cast<std::uint16_t *>(Ptr), ImageChannelOrder,
869  ImageChannelType),
871  break;
873  convertReadData<std::uint32_t>(
874  readPixel(reinterpret_cast<std::uint32_t *>(Ptr), ImageChannelOrder,
875  ImageChannelType),
877  break;
879  convertReadData<half>(readPixel(reinterpret_cast<half *>(Ptr),
880  ImageChannelOrder, ImageChannelType),
881  image_channel_type::fp16, Color);
882  break;
884  convertReadData<float>(readPixel(reinterpret_cast<float *>(Ptr),
885  ImageChannelOrder, ImageChannelType),
886  image_channel_type::fp32, Color);
887  break;
888  }
889 
890  return Color;
891 }
892 
893 // Checks if the PixelCoord is out-of-range, and returns appropriate border or
894 // color value at the PixelCoord.
895 template <typename DataT>
896 DataT getColor(const int4 PixelCoord, const addressing_mode SmplAddrMode,
897  const range<3> ImgRange, const id<3> ImgPitch,
898  const image_channel_type ImgChannelType,
899  const image_channel_order ImgChannelOrder, void *BasePtr,
900  const uint8_t ElementSize) {
901  DataT RetData;
902  if (isOutOfRange(PixelCoord, SmplAddrMode, ImgRange)) {
903  float4 BorderColor = getBorderColor(ImgChannelOrder);
904  RetData = BorderColor.convert<get_elem_type_t<DataT>>();
905  } else {
906  RetData = ReadPixelData<DataT>(PixelCoord, ImgPitch, ImgChannelType,
907  ImgChannelOrder, BasePtr, ElementSize);
908  }
909  return RetData;
910 }
911 
912 // Computes and returns color value with Linear Filter Mode.
913 // Steps:
914 // 1. Computes the 8 coordinates using all combinations of i0/i1,j0/j1,k0/k1.
915 // 2. Calls getColor() on each Coordinate.(Ci*j*k*)
916 // 3. Computes the return Color Value using a,b,c and the Color values.
917 template <typename DataT>
918 DataT ReadPixelDataLinearFiltMode(const int8 CoordValues, const float4 abc,
919  const addressing_mode SmplAddrMode,
920  const range<3> ImgRange, id<3> ImgPitch,
921  const image_channel_type ImgChannelType,
922  const image_channel_order ImgChannelOrder,
923  void *BasePtr, const uint8_t ElementSize) {
924  std::int32_t i0 = CoordValues.s0(), j0 = CoordValues.s1(),
925  k0 = CoordValues.s2(), i1 = CoordValues.s4(),
926  j1 = CoordValues.s5(), k1 = CoordValues.s6();
927 
928  auto getColorInFloat = [&](int4 V) {
929  DataT Res =
930  getColor<DataT>(V, SmplAddrMode, ImgRange, ImgPitch, ImgChannelType,
931  ImgChannelOrder, BasePtr, ElementSize);
932  return Res.template convert<float>();
933  };
934 
935  // Get Color Values at each Coordinate.
936  float4 Ci0j0k0 = getColorInFloat(int4{i0, j0, k0, 0});
937 
938  float4 Ci1j0k0 = getColorInFloat(int4{i1, j0, k0, 0});
939 
940  float4 Ci0j1k0 = getColorInFloat(int4{i0, j1, k0, 0});
941 
942  float4 Ci1j1k0 = getColorInFloat(int4{i1, j1, k0, 0});
943 
944  float4 Ci0j0k1 = getColorInFloat(int4{i0, j0, k1, 0});
945 
946  float4 Ci1j0k1 = getColorInFloat(int4{i1, j0, k1, 0});
947 
948  float4 Ci0j1k1 = getColorInFloat(int4{i0, j1, k1, 0});
949 
950  float4 Ci1j1k1 = getColorInFloat(int4{i1, j1, k1, 0});
951 
952  float a = abc.x();
953  float b = abc.y();
954  float c = abc.z();
955 
956  Ci0j0k0 = (1 - a) * (1 - b) * (1 - c) * Ci0j0k0;
957  Ci1j0k0 = a * (1 - b) * (1 - c) * Ci1j0k0;
958  Ci0j1k0 = (1 - a) * b * (1 - c) * Ci0j1k0;
959  Ci1j1k0 = a * b * (1 - c) * Ci1j1k0;
960  Ci0j0k1 = (1 - a) * (1 - b) * c * Ci0j0k1;
961  Ci1j0k1 = a * (1 - b) * c * Ci1j0k1;
962  Ci0j1k1 = (1 - a) * b * c * Ci0j1k1;
963  Ci1j1k1 = a * b * c * Ci1j1k1;
964 
965  float4 RetData = Ci0j0k0 + Ci1j0k0 + Ci0j1k0 + Ci1j1k0 + Ci0j0k1 + Ci1j0k1 +
966  Ci0j1k1 + Ci1j1k1;
967 
968  // For 2D image:k0 = 0, k1 = 0, c = 0.5
969  // RetData = (1 – a) * (1 – b) * Ci0j0 + a * (1 – b) * Ci1j0 +
970  // (1 – a) * b * Ci0j1 + a * b * Ci1j1;
971  // For 1D image: j0 = 0, j1 = 0, k0 = 0, k1 = 0, b = 0.5, c = 0.5.
972  // RetData = (1 – a) * Ci0 + a * Ci1;
973  return RetData.convert<get_elem_type_t<DataT>>();
974 }
975 
976 // imageReadSamplerHostImpl method is called by the read API in image accessors
977 // for host device.
978 // Algorithm used: The Algorithm is based on OpenCL spec section 8.2.
979 // It can be broken down into three major steps:
980 // Step 1.
981 // Check for valid sampler options and Compute u,v,w coordinates:
982 // These coordinates are used to compute the Pixel Coordinates that will be
983 // read from to compute the return values.
984 // u,v,w are normalized for AddrMode:mirror_repeat and repeat.
985 // u,v,w are unnormalized for AddrMode:clamp_to_edge, clamp, none.
986 // Convert normalized into unnormalized coords using image range.
987 // note: When dims=1, u,v,w={u,0,0}
988 // dims=2, u,v,w={u,v,0}
989 // dims=3, u,v,w-{u,v,w}
990 // Step 2.
991 // Process u,v,w, to find the exact Coordinates to read from:
992 // if(Nearest Filtering Mode)
993 // compute i,j,k pixel Coordinates based on AddrMode.
994 // else(Linear Filtering Mode)
995 // compute i0,j0,k0,i1,j1,k1,a,b,c values.
996 // Used to load following number of pixels in Step 3.
997 // 2x2x2 image for Dims=3
998 // 2x2 image for Dims=2
999 // 1 pixel for Dims=1 // I think same value should be
1000 // returned as nearest case.
1001 // Step 3.
1002 // Load Image Data, Different for Linear and Nearest Mode:
1003 // Offset = getOffset based on Coord, ImageRange,ImagePitch.
1004 // Read values in the appropriate format based on ImgChannelOrder and
1005 // ImgChannelType.
1006 // Convert to DataT as per conversion rules in section 8.3 in OpenCL Spec.
1007 //
1008 // TODO: Add additional check for half datatype read.
1009 // Based on OpenCL spec 2.0:
1010 // "The read_imageh calls that take integer coordinates must use a sampler with
1011 // filter mode set to CLK_FILTER_NEAREST, normalized coordinates set to
1012 // CLK_NORMALIZED_COORDS_FALSE and addressing mode set to
1013 // CLK_ADDRESS_CLAMP_TO_EDGE, CLK_ADDRESS_CLAMP or CLK_ADDRESS_NONE; otherwise
1014 // the values returned are undefined."
1015 
1016 template <typename CoordT, typename DataT>
1018  const CoordT &Coords, coordinate_normalization_mode SmplNormMode,
1019  addressing_mode SmplAddrMode, filtering_mode SmplFiltMode,
1020  /*All image information*/ range<3> ImgRange, id<3> ImgPitch,
1021  image_channel_type ImgChannelType, image_channel_order ImgChannelOrder,
1022  void *BasePtr, uint8_t ElementSize) {
1023 
1024  CoordT Coorduvw;
1025  float4 FloatCoorduvw;
1026  DataT RetData;
1027 
1028  // Step 1:
1029  // switch-case code is used for a better view on value of Coorduvw for all
1030  // combinations of Addressing Modes and Normalization Mode.
1031  switch (SmplNormMode) {
1033  switch (SmplAddrMode) {
1037  "Sampler used with unsupported configuration of "
1038  "mirrored_repeat/repeat filtering mode with "
1039  "unnormalized coordinates. ");
1042  case addressing_mode::none:
1043  // Continue with the unnormalized coordinates in Coorduvw.
1044  Coorduvw = Coords;
1045  break;
1046  }
1047  break; // Break for coordinate_normalization_mode::unnormalized.
1049  switch (SmplAddrMode) {
1052  // Continue with the normalized coordinates in Coorduvw.
1053  // Based on Section 8.2 Normalised coordinates are used to compute pixel
1054  // coordinates for addressing_mode::repeat and mirrored_repeat.
1055  Coorduvw = Coords;
1056  break;
1059  case addressing_mode::none:
1060  // Unnormalize these coordinates.
1061  // Based on Section 8.2 Normalised coordinats are used to compute pixel
1062  // coordinates for addressing_mode::clamp/clamp_to_edge and none.
1063  Coorduvw = UnnormalizeCoordinates(Coords, ImgRange);
1064  break;
1065  }
1066  break; // Break for coordinate_normalization_mode::normalized.
1067  }
1068 
1069  // Step 2 & Step 3:
1070 
1071  // converToFloat4 converts CoordT of any kind - std::int32_t, int2, int4,
1072  // float, float2 and float4 into Coordinates of kind float4 with no loss of
1073  // precision. For pixel_coordinates already in float4 format, the function
1074  // returns the same values. This conversion is done to enable implementation
1075  // of one common function getPixelCoordXXXMode, for any datatype of CoordT
1076  // passed.
1077  FloatCoorduvw = convertToFloat4(Coorduvw);
1078  switch (SmplFiltMode) {
1079  case filtering_mode::nearest: {
1080  // Get Pixel Coordinates in integers that will be read from in the Image.
1081  int4 PixelCoord =
1082  getPixelCoordNearestFiltMode(FloatCoorduvw, SmplAddrMode, ImgRange);
1083 
1084  // Return Border Color for out-of-range coordinates when Sampler has
1085  // addressing_mode::clamp. For all other cases and for in-range coordinates
1086  // read the color and return in DataT type.
1087  RetData =
1088  getColor<DataT>(PixelCoord, SmplAddrMode, ImgRange, ImgPitch,
1089  ImgChannelType, ImgChannelOrder, BasePtr, ElementSize);
1090  break;
1091  }
1092  case filtering_mode::linear: {
1093  float4 Retabc;
1094  // Get Pixel Coordinates in integers that will be read from in the Image.
1095  // Return i0,j0,k0,0,i1,j1,k1,0 to form 8 coordinates in a 3D image and
1096  // multiplication factors a,b,c
1097  int8 CoordValues = getPixelCoordLinearFiltMode(FloatCoorduvw, SmplAddrMode,
1098  ImgRange, Retabc);
1099 
1100  // Find the 8 coordinates with the values in CoordValues.
1101  // Computes the Color Value to return.
1102  RetData = ReadPixelDataLinearFiltMode<DataT>(
1103  CoordValues, Retabc, SmplAddrMode, ImgRange, ImgPitch, ImgChannelType,
1104  ImgChannelOrder, BasePtr, ElementSize);
1105 
1106  break;
1107  }
1108  }
1109 
1110  return RetData;
1111 }
1112 
1113 // SYCL 1.2.1 sampler overload.
1114 template <typename CoordT, typename DataT>
1115 DataT imageReadSamplerHostImpl(const CoordT &Coords, const sampler &Smpl,
1116  /*All image information*/ range<3> ImgRange,
1117  id<3> ImgPitch,
1118  image_channel_type ImgChannelType,
1119  image_channel_order ImgChannelOrder,
1120  void *BasePtr, uint8_t ElementSize) {
1121 
1122  coordinate_normalization_mode SmplNormMode =
1123  Smpl.get_coordinate_normalization_mode();
1124  addressing_mode SmplAddrMode = Smpl.get_addressing_mode();
1125  filtering_mode SmplFiltMode = Smpl.get_filtering_mode();
1126 
1127  return imageReadSamplerHostImpl<CoordT, DataT>(
1128  Coords, SmplNormMode, SmplAddrMode, SmplFiltMode, ImgRange, ImgPitch,
1129  ImgChannelType, ImgChannelOrder, BasePtr, ElementSize);
1130 }
1131 
1132 // SYCL 2020 image_sampler overload.
1133 template <typename CoordT, typename DataT>
1134 DataT imageReadSamplerHostImpl(const CoordT &Coords, const image_sampler &Smpl,
1135  /*All image information*/ range<3> ImgRange,
1136  id<3> ImgPitch,
1137  image_channel_type ImgChannelType,
1138  image_channel_order ImgChannelOrder,
1139  void *BasePtr, uint8_t ElementSize) {
1140  coordinate_normalization_mode SmplNormMode = Smpl.coordinate;
1141  addressing_mode SmplAddrMode = Smpl.addressing;
1142  filtering_mode SmplFiltMode = Smpl.filtering;
1143 
1144  return imageReadSamplerHostImpl<CoordT, DataT>(
1145  Coords, SmplNormMode, SmplAddrMode, SmplFiltMode, ImgRange, ImgPitch,
1146  ImgChannelType, ImgChannelOrder, BasePtr, ElementSize);
1147 }
1148 
1149 } // namespace detail
1150 } // namespace _V1
1151 } // namespace sycl
1152 #endif
float4 getBorderColor(const image_channel_order ImgChannelOrder)
int4 getPixelCoordNearestFiltMode(float4, const addressing_mode, const range< 3 >)
DataT imageReadSamplerHostImpl(const CoordT &Coords, coordinate_normalization_mode SmplNormMode, addressing_mode SmplAddrMode, filtering_mode SmplFiltMode, range< 3 > ImgRange, id< 3 > ImgPitch, image_channel_type ImgChannelType, image_channel_order ImgChannelOrder, void *BasePtr, uint8_t ElementSize)
bool isOutOfRange(const int4 PixelCoord, const addressing_mode SmplAddrMode, const range< 3 > ImgRange)
DataT getColor(const int4 PixelCoord, const addressing_mode SmplAddrMode, const range< 3 > ImgRange, const id< 3 > ImgPitch, const image_channel_type ImgChannelType, const image_channel_order ImgChannelOrder, void *BasePtr, const uint8_t ElementSize)
void imageWriteHostImpl(const CoordT &Coords, const WriteDataT &Color, id< 3 > ImgPitch, uint8_t ElementSize, image_channel_type ImgChannelType, image_channel_order ImgChannelOrder, void *BasePtr)
void writePixel(const vec< T, 4 > Pixel, T *Ptr, const image_channel_order ChannelOrder, const image_channel_type ChannelType)
boost::mp11::mp_set_contains< TypeList, std::remove_cv_t< T > > is_contained
Definition: type_list.hpp:32
typename get_elem_type< T >::type get_elem_type_t
int8 getPixelCoordLinearFiltMode(float4, const addressing_mode, const range< 3 >, float4 &)
vec< T, 4 > readPixel(T *Ptr, const image_channel_order ChannelOrder, const image_channel_type ChannelType)
boost::mp11::mp_list< T... > type_list
Definition: type_list.hpp:22
std::enable_if_t< std::is_integral_v< T >, size_t > getImageOffset(const T &Coords, const id< 3 >, const uint8_t ElementSize)
vec< ChannelType, 4 > processFloatDataToPixel(float4 WriteData, float MulFactor)
DataT ReadPixelData(const int4 PixelCoord, const id< 3 > ImgPitch, const image_channel_type ImageChannelType, const image_channel_order ImageChannelOrder, void *BasePtr, const uint8_t ElementSize)
typename is_contained< T, boost::mp11::mp_unique< type_list< opencl::cl_int, opencl::cl_float, std::int32_t, float > >>::type IsValidCoordType
void convertReadData(const vec< ChannelType, 4 > PixelData, const image_channel_type ImageChannelType, uint4 &RetData)
DataT ReadPixelDataLinearFiltMode(const int8 CoordValues, const float4 abc, const addressing_mode SmplAddrMode, const range< 3 > ImgRange, id< 3 > ImgPitch, const image_channel_type ImgChannelType, const image_channel_order ImgChannelOrder, void *BasePtr, const uint8_t ElementSize)
std::enable_if_t< IsValidCoordType< T >::value, float4 > convertToFloat4(T Coords)
std::enable_if_t< IsValidCoordType< T >::value, T > UnnormalizeCoordinates(const T &Coords, const range< 3 > &Range)
vec< ChannelType, 4 > convertWriteData(const uint4 WriteData, const image_channel_type ImageChannelType)
std::int32_t cl_int
Definition: aliases.hpp:134
filtering_mode
Definition: sampler.hpp:31
coordinate_normalization_mode
Definition: sampler.hpp:36
auto autodecltype(a) b
addressing_mode
Definition: sampler.hpp:23
image_channel_order
Definition: image.hpp:56
image_channel_type
Definition: image.hpp:74
std::error_code make_error_code(sycl::errc E) noexcept
Constructs an error code using e and sycl_category()
Definition: exception.cpp:65
Definition: access.hpp:18
addressing_mode addressing
Definition: sampler.hpp:140
coordinate_normalization_mode coordinate
Definition: sampler.hpp:141
filtering_mode filtering
Definition: sampler.hpp:142