DPC++ Runtime
Runtime libraries for oneAPI DPC++
image_impl.cpp
Go to the documentation of this file.
1 //==------------ image_impl.cpp --------------------------------------------==//
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 
10 #include <detail/image_impl.hpp>
12 
13 #include <algorithm>
14 #include <vector>
15 
16 namespace sycl {
18 namespace detail {
19 
20 template <typename Param>
21 static bool checkImageValueRange(const std::vector<device> &Devices,
22  const size_t Value) {
23  return Value >= 1 && std::all_of(Devices.cbegin(), Devices.cend(),
24  [Value](const device &Dev) {
25  return Value <= Dev.get_info<Param>();
26  });
27 }
28 
29 template <typename T, typename... Args> static bool checkAnyImpl(T) {
30  return false;
31 }
32 
33 template <typename ValT, typename VarT, typename... Args>
34 static bool checkAnyImpl(ValT Value, VarT Variant, Args... Arguments) {
35  return (Value == Variant) ? true : checkAnyImpl(Value, Arguments...);
36 }
37 
38 template <typename T, typename... Args>
39 static bool checkAny(const T Value, Args... Arguments) {
40  return checkAnyImpl(Value, Arguments...);
41 }
42 
44  switch (Order) {
45  case image_channel_order::a:
46  case image_channel_order::r:
47  case image_channel_order::rx:
48  case image_channel_order::intensity:
49  case image_channel_order::luminance:
50  return 1;
51  case image_channel_order::rg:
52  case image_channel_order::rgx:
53  case image_channel_order::ra:
54  return 2;
55  case image_channel_order::rgb:
56  return 3;
57  case image_channel_order::rgbx:
58  case image_channel_order::rgba:
59  case image_channel_order::argb:
60  case image_channel_order::bgra:
61  case image_channel_order::abgr:
62  case image_channel_order::ext_oneapi_srgba:
63  return 4;
64  }
65  assert(false && "Unhandled image channel order");
66  return 0;
67 }
68 
69 // Returns the number of bytes per image element
70 uint8_t getImageElementSize(uint8_t NumChannels, image_channel_type Type) {
71  size_t Retval = 0;
72  switch (Type) {
73  case image_channel_type::snorm_int8:
74  case image_channel_type::unorm_int8:
75  case image_channel_type::signed_int8:
76  case image_channel_type::unsigned_int8:
77  Retval = NumChannels;
78  break;
79  case image_channel_type::snorm_int16:
80  case image_channel_type::unorm_int16:
81  case image_channel_type::signed_int16:
82  case image_channel_type::unsigned_int16:
83  case image_channel_type::fp16:
84  Retval = 2 * NumChannels;
85  break;
86  case image_channel_type::signed_int32:
87  case image_channel_type::unsigned_int32:
88  case image_channel_type::fp32:
89  Retval = 4 * NumChannels;
90  break;
91  case image_channel_type::unorm_short_565:
92  case image_channel_type::unorm_short_555:
93  Retval = 2;
94  break;
95  case image_channel_type::unorm_int_101010:
96  Retval = 4;
97  break;
98  }
99  // OpenCL states that "The number of bits per element determined by the
100  // image_channel_type and image_channel_order must be a power of two"
101  // Retval is in bytes. The formula remains the same for bytes or bits.
102  assert(((Retval - 1) & Retval) == 0);
103  return Retval;
104 }
105 
107  switch (Order) {
108  case image_channel_order::a:
110  case image_channel_order::r:
112  case image_channel_order::rx:
114  case image_channel_order::rg:
116  case image_channel_order::rgx:
118  case image_channel_order::ra:
120  case image_channel_order::rgb:
122  case image_channel_order::rgbx:
124  case image_channel_order::rgba:
126  case image_channel_order::argb:
128  case image_channel_order::bgra:
130  case image_channel_order::intensity:
132  case image_channel_order::luminance:
134  case image_channel_order::abgr:
136  case image_channel_order::ext_oneapi_srgba:
138  }
139  assert(false && "Unhandled image_channel_order");
140  return static_cast<RT::PiMemImageChannelOrder>(0);
141 }
142 
144  switch (Order) {
146  return image_channel_order::a;
148  return image_channel_order::r;
150  return image_channel_order::rx;
152  return image_channel_order::rg;
154  return image_channel_order::rgx;
156  return image_channel_order::ra;
158  return image_channel_order::rgb;
160  return image_channel_order::rgbx;
162  return image_channel_order::rgba;
164  return image_channel_order::argb;
166  return image_channel_order::bgra;
168  return image_channel_order::intensity;
170  return image_channel_order::luminance;
172  return image_channel_order::abgr;
174  return image_channel_order::ext_oneapi_srgba;
175  }
176  assert(false && "Unhandled image_channel_order");
177  return static_cast<image_channel_order>(0);
178 }
179 
181  switch (Type) {
182  case image_channel_type::snorm_int8:
184  case image_channel_type::snorm_int16:
186  case image_channel_type::unorm_int8:
188  case image_channel_type::unorm_int16:
190  case image_channel_type::unorm_short_565:
192  case image_channel_type::unorm_short_555:
194  case image_channel_type::unorm_int_101010:
196  case image_channel_type::signed_int8:
198  case image_channel_type::signed_int16:
200  case image_channel_type::signed_int32:
202  case image_channel_type::unsigned_int8:
204  case image_channel_type::unsigned_int16:
206  case image_channel_type::unsigned_int32:
208  case image_channel_type::fp16:
210  case image_channel_type::fp32:
212  }
213  assert(false && "Unhandled image_channel_order");
214  return static_cast<RT::PiMemImageChannelType>(0);
215 }
216 
218  switch (Type) {
220  return image_channel_type::snorm_int8;
222  return image_channel_type::snorm_int16;
224  return image_channel_type::unorm_int8;
226  return image_channel_type::unorm_int16;
228  return image_channel_type::unorm_short_565;
230  return image_channel_type::unorm_short_555;
232  return image_channel_type::unorm_int_101010;
234  return image_channel_type::signed_int8;
236  return image_channel_type::signed_int16;
238  return image_channel_type::signed_int32;
240  return image_channel_type::unsigned_int8;
242  return image_channel_type::unsigned_int16;
244  return image_channel_type::unsigned_int32;
246  return image_channel_type::fp16;
248  return image_channel_type::fp32;
249  }
250  assert(false && "Unhandled image_channel_order");
251  return static_cast<image_channel_type>(0);
252 }
253 
254 template <typename T>
255 static void getImageInfo(const ContextImplPtr Context, RT::PiMemImageInfo Info,
256  T &Dest, RT::PiMem InteropMemObject) {
257  const detail::plugin &Plugin = Context->getPlugin();
258  RT::PiMem Mem = pi::cast<RT::PiMem>(InteropMemObject);
259  Plugin.call<PiApiKind::piMemImageGetInfo>(Mem, Info, sizeof(T), &Dest,
260  nullptr);
261 }
262 
263 image_impl::image_impl(cl_mem MemObject, const context &SyclContext,
264  event AvailableEvent,
265  std::unique_ptr<SYCLMemObjAllocator> Allocator,
266  uint8_t Dimensions)
267  : BaseT(MemObject, SyclContext, std::move(AvailableEvent),
268  std::move(Allocator)),
269  MDimensions(Dimensions), MRange({0, 0, 0}) {
270  RT::PiMem Mem = pi::cast<RT::PiMem>(BaseT::MInteropMemObject);
271  const ContextImplPtr Context = getSyclObjImpl(SyclContext);
272  const detail::plugin &Plugin = Context->getPlugin();
273  Plugin.call<PiApiKind::piMemGetInfo>(Mem, PI_MEM_SIZE, sizeof(size_t),
274  &(BaseT::MSizeInBytes), nullptr);
275 
276  RT::PiMemImageFormat Format;
277  getImageInfo(Context, PI_IMAGE_INFO_FORMAT, Format, Mem);
278  MOrder = detail::convertChannelOrder(Format.image_channel_order);
279  MType = detail::convertChannelType(Format.image_channel_data_type);
280  MNumChannels = getImageNumberChannels(MOrder);
281 
282  getImageInfo(Context, PI_IMAGE_INFO_ELEMENT_SIZE, MElementSize, Mem);
283  assert(getImageElementSize(MNumChannels, MType) == MElementSize);
284 
285  getImageInfo(Context, PI_IMAGE_INFO_ROW_PITCH, MRowPitch, Mem);
286  getImageInfo(Context, PI_IMAGE_INFO_SLICE_PITCH, MSlicePitch, Mem);
287 
288  switch (MDimensions) {
289  case 3:
290  getImageInfo(Context, PI_IMAGE_INFO_DEPTH, MRange[2], Mem);
292  case 2:
293  getImageInfo(Context, PI_IMAGE_INFO_HEIGHT, MRange[1], Mem);
295  case 1:
296  getImageInfo(Context, PI_IMAGE_INFO_WIDTH, MRange[0], Mem);
297  }
298 }
299 
300 void *image_impl::allocateMem(ContextImplPtr Context, bool InitFromUserData,
301  void *HostPtr, RT::PiEvent &OutEventToWait) {
302  bool HostPtrReadOnly = false;
303  BaseT::determineHostPtr(Context, InitFromUserData, HostPtr, HostPtrReadOnly);
304 
305  RT::PiMemImageDesc Desc = getImageDesc(HostPtr != nullptr);
306  assert(checkImageDesc(Desc, Context, HostPtr) &&
307  "The check an image desc failed.");
308 
309  RT::PiMemImageFormat Format = getImageFormat();
310  assert(checkImageFormat(Format, Context) &&
311  "The check an image format failed.");
312 
314  std::move(Context), this, HostPtr, HostPtrReadOnly,
316  BaseT::MInteropContext, MProps, OutEventToWait);
317 }
318 
319 bool image_impl::checkImageDesc(const RT::PiMemImageDesc &Desc,
320  ContextImplPtr Context, void *UserPtr) {
323  !checkImageValueRange<info::device::image2d_max_width>(
324  getDevices(Context), Desc.image_width))
325  throw invalid_parameter_error(
326  "For a 1D/2D image/image array, the width must be a Value >= 1 and "
327  "<= info::device::image2d_max_width",
328  PI_ERROR_INVALID_VALUE);
329 
330  if (checkAny(Desc.image_type, PI_MEM_TYPE_IMAGE3D) &&
331  !checkImageValueRange<info::device::image3d_max_width>(
332  getDevices(Context), Desc.image_width))
333  throw invalid_parameter_error(
334  "For a 3D image, the width must be a Value >= 1 and <= "
335  "info::device::image3d_max_width",
336  PI_ERROR_INVALID_VALUE);
337 
338  if (checkAny(Desc.image_type, PI_MEM_TYPE_IMAGE2D,
340  !checkImageValueRange<info::device::image2d_max_height>(
341  getDevices(Context), Desc.image_height))
342  throw invalid_parameter_error("For a 2D image or image array, the height "
343  "must be a Value >= 1 and <= "
344  "info::device::image2d_max_height",
345  PI_ERROR_INVALID_VALUE);
346 
347  if (checkAny(Desc.image_type, PI_MEM_TYPE_IMAGE3D) &&
348  !checkImageValueRange<info::device::image3d_max_height>(
349  getDevices(Context), Desc.image_height))
350  throw invalid_parameter_error(
351  "For a 3D image, the heightmust be a Value >= 1 and <= "
352  "info::device::image3d_max_height",
353  PI_ERROR_INVALID_VALUE);
354 
355  if (checkAny(Desc.image_type, PI_MEM_TYPE_IMAGE3D) &&
356  !checkImageValueRange<info::device::image3d_max_depth>(
357  getDevices(Context), Desc.image_depth))
358  throw invalid_parameter_error(
359  "For a 3D image, the depth must be a Value >= 1 and <= "
360  "info::device::image2d_max_depth",
361  PI_ERROR_INVALID_VALUE);
362 
363  if (checkAny(Desc.image_type, PI_MEM_TYPE_IMAGE1D_ARRAY,
365  !checkImageValueRange<info::device::image_max_array_size>(
366  getDevices(Context), Desc.image_array_size))
367  throw invalid_parameter_error(
368  "For a 1D and 2D image array, the array_size must be a "
369  "Value >= 1 and <= info::device::image_max_array_size.",
370  PI_ERROR_INVALID_VALUE);
371 
372  if ((nullptr == UserPtr) && (0 != Desc.image_row_pitch))
373  throw invalid_parameter_error(
374  "The row_pitch must be 0 if host_ptr is nullptr.",
375  PI_ERROR_INVALID_VALUE);
376 
377  if ((nullptr == UserPtr) && (0 != Desc.image_slice_pitch))
378  throw invalid_parameter_error(
379  "The slice_pitch must be 0 if host_ptr is nullptr.",
380  PI_ERROR_INVALID_VALUE);
381 
382  if (0 != Desc.num_mip_levels)
383  throw invalid_parameter_error("The mip_levels must be 0.",
384  PI_ERROR_INVALID_VALUE);
385 
386  if (0 != Desc.num_samples)
387  throw invalid_parameter_error("The num_samples must be 0.",
388  PI_ERROR_INVALID_VALUE);
389 
390  if (nullptr != Desc.buffer)
391  throw invalid_parameter_error(
392  "The buffer must be nullptr, because SYCL does not support "
393  "image creation from memory objects.",
394  PI_ERROR_INVALID_VALUE);
395 
396  return true;
397 }
398 
399 bool image_impl::checkImageFormat(const RT::PiMemImageFormat &Format,
400  ContextImplPtr Context) {
401  (void)Context;
402  if (checkAny(Format.image_channel_order, PI_IMAGE_CHANNEL_ORDER_INTENSITY,
404  !checkAny(
405  Format.image_channel_data_type, PI_IMAGE_CHANNEL_TYPE_UNORM_INT8,
409  throw invalid_parameter_error(
410  "CL_INTENSITY or CL_LUMINANCE format can only be used if channel "
411  "data type = CL_UNORM_INT8, CL_UNORM_INT16, CL_SNORM_INT8, "
412  "CL_SNORM_INT16, CL_HALF_FLOAT, or CL_FLOAT.",
413  PI_ERROR_INVALID_VALUE);
414 
415  if (checkAny(Format.image_channel_data_type,
419  !checkAny(Format.image_channel_order, PI_IMAGE_CHANNEL_ORDER_RGB,
421  throw invalid_parameter_error(
422  "type = CL_UNORM_SHORT_565, CL_UNORM_SHORT_555 or "
423  "CL_UNORM_INT_101010."
424  "These channel types can only be used with CL_RGB or CL_RGBx channel "
425  "order.",
426  PI_ERROR_INVALID_VALUE);
427 
428  if (checkAny(Format.image_channel_order, PI_IMAGE_CHANNEL_ORDER_ARGB,
430  !checkAny(
431  Format.image_channel_data_type, PI_IMAGE_CHANNEL_TYPE_UNORM_INT8,
434  throw invalid_parameter_error(
435  "CL_ARGB, CL_BGRA, CL_ABGR These formats can only be used if "
436  "channel data type = CL_UNORM_INT8, CL_SNORM_INT8, CL_SIGNED_INT8 "
437  "or CL_UNSIGNED_INT8.",
438  PI_ERROR_INVALID_VALUE);
439 
440  return true;
441 }
442 
443 std::vector<device> image_impl::getDevices(const ContextImplPtr Context) {
444  return Context->get_info<info::context::devices>();
445 }
446 
447 } // namespace detail
448 } // __SYCL_INLINE_VER_NAMESPACE(_V1)
449 } // namespace sycl
The context class represents a SYCL context on which kernel functions may be executed.
Definition: context.hpp:39
static void * allocateMemImage(ContextImplPtr TargetContext, SYCLMemObjI *MemObj, void *UserPtr, bool HostPtrReadOnly, size_t Size, const RT::PiMemImageDesc &Desc, const RT::PiMemImageFormat &Format, const EventImplPtr &InteropEvent, const ContextImplPtr &InteropContext, const sycl::property_list &PropsList, RT::PiEvent &OutEventToWait)
void determineHostPtr(const ContextImplPtr &Context, bool InitFromUserData, void *&HostPtr, bool &HostPtrReadOnly)
size_t getSizeInBytes() const override
void * allocateMem(ContextImplPtr Context, bool InitFromUserData, void *HostPtr, RT::PiEvent &OutEventToWait) override
Definition: image_impl.cpp:300
The plugin class provides a unified interface to the underlying low-level runtimes for the device-agn...
Definition: plugin.hpp:90
void call(ArgsT... Args) const
Calls the API, traces the call, checks the result.
Definition: plugin.hpp:217
The SYCL device class encapsulates a single SYCL device on which kernels may be executed.
Definition: device.hpp:47
An event object can be used to synchronize memory transfers, enqueues of kernels and signaling barrie...
Definition: event.hpp:38
#define __SYCL_FALLTHROUGH
#define __SYCL_INLINE_VER_NAMESPACE(X)
::pi_event PiEvent
Definition: pi.hpp:121
::pi_image_channel_type PiMemImageChannelType
Definition: pi.hpp:132
::pi_image_info PiMemImageInfo
Definition: pi.hpp:129
::pi_mem PiMem
Definition: pi.hpp:119
::pi_image_channel_order PiMemImageChannelOrder
Definition: pi.hpp:131
::pi_image_desc PiMemImageDesc
Definition: pi.hpp:128
::pi_image_format PiMemImageFormat
Definition: pi.hpp:127
RT::PiMemImageChannelOrder convertChannelOrder(image_channel_order Order)
Definition: image_impl.cpp:106
uint8_t getImageElementSize(uint8_t NumChannels, image_channel_type Type)
Definition: image_impl.cpp:70
static bool checkAny(const T Value, Args... Arguments)
Definition: image_impl.cpp:39
std::shared_ptr< sycl::detail::context_impl > ContextImplPtr
Definition: event_impl.hpp:30
decltype(Obj::impl) getSyclObjImpl(const Obj &SyclObject)
Definition: common.hpp:240
static bool checkImageValueRange(const std::vector< device > &Devices, const size_t Value)
Definition: image_impl.cpp:21
static bool checkAnyImpl(ValT Value, VarT Variant, Args... Arguments)
Definition: image_impl.cpp:34
RT::PiMemImageChannelType convertChannelType(image_channel_type Type)
Definition: image_impl.cpp:180
image_channel_order convertChannelOrder(RT::PiMemImageChannelOrder Order)
Definition: image_impl.cpp:143
image_channel_type convertChannelType(RT::PiMemImageChannelType Type)
Definition: image_impl.cpp:217
uint8_t getImageNumberChannels(image_channel_order Order)
Definition: image_impl.cpp:43
static void getImageInfo(const ContextImplPtr Context, RT::PiMemImageInfo Info, T &Dest, RT::PiMem InteropMemObject)
Definition: image_impl.cpp:255
std::shared_ptr< sycl::detail::context_impl > ContextImplPtr
Definition: helpers.cpp:19
class __SYCL_SPECIAL_CLASS __SYCL_TYPE(local_accessor) local_accessor class __SYCL_SPECIAL_CLASS Dimensions
Definition: accessor.hpp:2747
image_channel_order
Definition: image.hpp:27
image_channel_type
Definition: image.hpp:45
---— Error handling, matching OpenCL plugin semantics.
Definition: access.hpp:14
pi_result piMemImageGetInfo(pi_mem image, pi_image_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret)
@ PI_IMAGE_CHANNEL_TYPE_FLOAT
Definition: pi.h:471
@ PI_IMAGE_CHANNEL_TYPE_UNORM_SHORT_565
Definition: pi.h:461
@ PI_IMAGE_CHANNEL_TYPE_UNORM_INT8
Definition: pi.h:459
@ PI_IMAGE_CHANNEL_TYPE_SIGNED_INT16
Definition: pi.h:465
@ PI_IMAGE_CHANNEL_TYPE_SNORM_INT16
Definition: pi.h:458
@ PI_IMAGE_CHANNEL_TYPE_UNSIGNED_INT8
Definition: pi.h:467
@ PI_IMAGE_CHANNEL_TYPE_SIGNED_INT8
Definition: pi.h:464
@ PI_IMAGE_CHANNEL_TYPE_UNORM_INT_101010
Definition: pi.h:463
@ PI_IMAGE_CHANNEL_TYPE_UNSIGNED_INT32
Definition: pi.h:469
@ PI_IMAGE_CHANNEL_TYPE_UNSIGNED_INT16
Definition: pi.h:468
@ PI_IMAGE_CHANNEL_TYPE_SNORM_INT8
Definition: pi.h:457
@ PI_IMAGE_CHANNEL_TYPE_UNORM_SHORT_555
Definition: pi.h:462
@ PI_IMAGE_CHANNEL_TYPE_SIGNED_INT32
Definition: pi.h:466
@ PI_IMAGE_CHANNEL_TYPE_HALF_FLOAT
Definition: pi.h:470
@ PI_IMAGE_CHANNEL_TYPE_UNORM_INT16
Definition: pi.h:460
pi_result piMemGetInfo(pi_mem mem, pi_mem_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret)
@ PI_IMAGE_INFO_HEIGHT
Definition: pi.h:361
@ PI_IMAGE_INFO_SLICE_PITCH
Definition: pi.h:359
@ PI_IMAGE_INFO_ROW_PITCH
Definition: pi.h:358
@ PI_IMAGE_INFO_WIDTH
Definition: pi.h:360
@ PI_IMAGE_INFO_FORMAT
Definition: pi.h:356
@ PI_IMAGE_INFO_ELEMENT_SIZE
Definition: pi.h:357
@ PI_IMAGE_INFO_DEPTH
Definition: pi.h:362
@ PI_IMAGE_CHANNEL_ORDER_RGB
Definition: pi.h:443
@ PI_IMAGE_CHANNEL_ORDER_RA
Definition: pi.h:442
@ PI_IMAGE_CHANNEL_ORDER_RGBA
Definition: pi.h:444
@ PI_IMAGE_CHANNEL_ORDER_INTENSITY
Definition: pi.h:448
@ PI_IMAGE_CHANNEL_ORDER_R
Definition: pi.h:440
@ PI_IMAGE_CHANNEL_ORDER_ABGR
Definition: pi.h:447
@ PI_IMAGE_CHANNEL_ORDER_RGBx
Definition: pi.h:452
@ PI_IMAGE_CHANNEL_ORDER_RG
Definition: pi.h:441
@ PI_IMAGE_CHANNEL_ORDER_BGRA
Definition: pi.h:445
@ PI_IMAGE_CHANNEL_ORDER_Rx
Definition: pi.h:450
@ PI_IMAGE_CHANNEL_ORDER_A
Definition: pi.h:439
@ PI_IMAGE_CHANNEL_ORDER_sRGBA
Definition: pi.h:453
@ PI_IMAGE_CHANNEL_ORDER_LUMINANCE
Definition: pi.h:449
@ PI_IMAGE_CHANNEL_ORDER_RGx
Definition: pi.h:451
@ PI_IMAGE_CHANNEL_ORDER_ARGB
Definition: pi.h:446
@ PI_MEM_TYPE_IMAGE1D
Definition: pi.h:417
@ PI_MEM_TYPE_IMAGE1D_ARRAY
Definition: pi.h:418
@ PI_MEM_TYPE_IMAGE2D
Definition: pi.h:414
@ PI_MEM_TYPE_IMAGE2D_ARRAY
Definition: pi.h:416
@ PI_MEM_TYPE_IMAGE3D
Definition: pi.h:415
@ PI_MEM_SIZE
Definition: pi.h:934
bool all_of(const simd_mask< _Tp, _Abi > &) noexcept