1bf215546Sopenharmony_ci//
2bf215546Sopenharmony_ci// Copyright 2012 Francisco Jerez
3bf215546Sopenharmony_ci//
4bf215546Sopenharmony_ci// Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci// copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci// to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci// and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci// Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci//
11bf215546Sopenharmony_ci// The above copyright notice and this permission notice shall be included in
12bf215546Sopenharmony_ci// all copies or substantial portions of the Software.
13bf215546Sopenharmony_ci//
14bf215546Sopenharmony_ci// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15bf215546Sopenharmony_ci// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16bf215546Sopenharmony_ci// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17bf215546Sopenharmony_ci// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18bf215546Sopenharmony_ci// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19bf215546Sopenharmony_ci// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20bf215546Sopenharmony_ci// OTHER DEALINGS IN THE SOFTWARE.
21bf215546Sopenharmony_ci//
22bf215546Sopenharmony_ci
23bf215546Sopenharmony_ci#include "util/format/u_format.h"
24bf215546Sopenharmony_ci#include "util/u_math.h"
25bf215546Sopenharmony_ci#include "api/util.hpp"
26bf215546Sopenharmony_ci#include "core/memory.hpp"
27bf215546Sopenharmony_ci#include "core/format.hpp"
28bf215546Sopenharmony_ci
29bf215546Sopenharmony_ciusing namespace clover;
30bf215546Sopenharmony_ci
31bf215546Sopenharmony_cinamespace {
32bf215546Sopenharmony_ci   cl_mem_flags
33bf215546Sopenharmony_ci   validate_flags(cl_mem d_parent, cl_mem_flags d_flags, bool svm) {
34bf215546Sopenharmony_ci      const cl_mem_flags dev_access_flags =
35bf215546Sopenharmony_ci         CL_MEM_READ_WRITE | CL_MEM_WRITE_ONLY | CL_MEM_READ_ONLY;
36bf215546Sopenharmony_ci      const cl_mem_flags host_ptr_flags =
37bf215546Sopenharmony_ci         CL_MEM_USE_HOST_PTR | CL_MEM_ALLOC_HOST_PTR | CL_MEM_COPY_HOST_PTR;
38bf215546Sopenharmony_ci      const cl_mem_flags host_access_flags =
39bf215546Sopenharmony_ci         CL_MEM_HOST_WRITE_ONLY | CL_MEM_HOST_READ_ONLY | CL_MEM_HOST_NO_ACCESS;
40bf215546Sopenharmony_ci      const cl_mem_flags svm_flags =
41bf215546Sopenharmony_ci         CL_MEM_SVM_FINE_GRAIN_BUFFER | CL_MEM_SVM_ATOMICS;
42bf215546Sopenharmony_ci
43bf215546Sopenharmony_ci      const cl_mem_flags valid_flags =
44bf215546Sopenharmony_ci         dev_access_flags
45bf215546Sopenharmony_ci            | (svm || d_parent ? 0 : host_ptr_flags)
46bf215546Sopenharmony_ci            | (svm ? svm_flags : host_access_flags);
47bf215546Sopenharmony_ci
48bf215546Sopenharmony_ci      if ((d_flags & ~valid_flags) ||
49bf215546Sopenharmony_ci          util_bitcount(d_flags & dev_access_flags) > 1 ||
50bf215546Sopenharmony_ci          util_bitcount(d_flags & host_access_flags) > 1)
51bf215546Sopenharmony_ci         throw error(CL_INVALID_VALUE);
52bf215546Sopenharmony_ci
53bf215546Sopenharmony_ci      if ((d_flags & CL_MEM_USE_HOST_PTR) &&
54bf215546Sopenharmony_ci          (d_flags & (CL_MEM_COPY_HOST_PTR | CL_MEM_ALLOC_HOST_PTR)))
55bf215546Sopenharmony_ci         throw error(CL_INVALID_VALUE);
56bf215546Sopenharmony_ci
57bf215546Sopenharmony_ci      if ((d_flags & CL_MEM_SVM_ATOMICS) &&
58bf215546Sopenharmony_ci          !(d_flags & CL_MEM_SVM_FINE_GRAIN_BUFFER))
59bf215546Sopenharmony_ci         throw error(CL_INVALID_VALUE);
60bf215546Sopenharmony_ci
61bf215546Sopenharmony_ci      if (d_parent) {
62bf215546Sopenharmony_ci         const auto &parent = obj(d_parent);
63bf215546Sopenharmony_ci         const cl_mem_flags flags = (d_flags |
64bf215546Sopenharmony_ci                                     (d_flags & dev_access_flags ? 0 :
65bf215546Sopenharmony_ci                                      parent.flags() & dev_access_flags) |
66bf215546Sopenharmony_ci                                     (d_flags & host_access_flags ? 0 :
67bf215546Sopenharmony_ci                                      parent.flags() & host_access_flags) |
68bf215546Sopenharmony_ci                                     (parent.flags() & host_ptr_flags));
69bf215546Sopenharmony_ci
70bf215546Sopenharmony_ci         if (~flags & parent.flags() & (dev_access_flags & ~CL_MEM_READ_WRITE))
71bf215546Sopenharmony_ci            throw error(CL_INVALID_VALUE);
72bf215546Sopenharmony_ci
73bf215546Sopenharmony_ci         // Check if new host access flags cause a mismatch between
74bf215546Sopenharmony_ci         // host-read/write-only.
75bf215546Sopenharmony_ci         if (!(flags & CL_MEM_HOST_NO_ACCESS) &&
76bf215546Sopenharmony_ci             (~flags & parent.flags() & host_access_flags))
77bf215546Sopenharmony_ci            throw error(CL_INVALID_VALUE);
78bf215546Sopenharmony_ci
79bf215546Sopenharmony_ci         return flags;
80bf215546Sopenharmony_ci
81bf215546Sopenharmony_ci      } else {
82bf215546Sopenharmony_ci         return d_flags | (d_flags & dev_access_flags ? 0 : CL_MEM_READ_WRITE);
83bf215546Sopenharmony_ci      }
84bf215546Sopenharmony_ci   }
85bf215546Sopenharmony_ci
86bf215546Sopenharmony_ci   std::vector<cl_mem_properties>
87bf215546Sopenharmony_ci   fill_properties(const cl_mem_properties *d_properties) {
88bf215546Sopenharmony_ci      std::vector<cl_mem_properties> properties;
89bf215546Sopenharmony_ci      if (d_properties) {
90bf215546Sopenharmony_ci         while (*d_properties) {
91bf215546Sopenharmony_ci            if (*d_properties != 0)
92bf215546Sopenharmony_ci               throw error(CL_INVALID_PROPERTY);
93bf215546Sopenharmony_ci
94bf215546Sopenharmony_ci            properties.push_back(*d_properties);
95bf215546Sopenharmony_ci            d_properties++;
96bf215546Sopenharmony_ci         };
97bf215546Sopenharmony_ci         properties.push_back(0);
98bf215546Sopenharmony_ci      }
99bf215546Sopenharmony_ci      return properties;
100bf215546Sopenharmony_ci   }
101bf215546Sopenharmony_ci}
102bf215546Sopenharmony_ci
103bf215546Sopenharmony_ciCLOVER_API cl_mem
104bf215546Sopenharmony_ciclCreateBufferWithProperties(cl_context d_ctx,
105bf215546Sopenharmony_ci                             const cl_mem_properties *d_properties,
106bf215546Sopenharmony_ci                             cl_mem_flags d_flags, size_t size,
107bf215546Sopenharmony_ci                             void *host_ptr, cl_int *r_errcode) try {
108bf215546Sopenharmony_ci
109bf215546Sopenharmony_ci   auto &ctx = obj(d_ctx);
110bf215546Sopenharmony_ci   const cl_mem_flags flags = validate_flags(NULL, d_flags, false);
111bf215546Sopenharmony_ci   std::vector<cl_mem_properties> properties = fill_properties(d_properties);
112bf215546Sopenharmony_ci
113bf215546Sopenharmony_ci   if (bool(host_ptr) != bool(flags & (CL_MEM_USE_HOST_PTR |
114bf215546Sopenharmony_ci                                       CL_MEM_COPY_HOST_PTR)))
115bf215546Sopenharmony_ci      throw error(CL_INVALID_HOST_PTR);
116bf215546Sopenharmony_ci
117bf215546Sopenharmony_ci   if (!size ||
118bf215546Sopenharmony_ci       size > fold(maximum(), cl_ulong(0),
119bf215546Sopenharmony_ci                   map(std::mem_fn(&device::max_mem_alloc_size), ctx.devices())
120bf215546Sopenharmony_ci          ))
121bf215546Sopenharmony_ci      throw error(CL_INVALID_BUFFER_SIZE);
122bf215546Sopenharmony_ci
123bf215546Sopenharmony_ci   ret_error(r_errcode, CL_SUCCESS);
124bf215546Sopenharmony_ci   return new root_buffer(ctx, properties, flags, size, host_ptr);
125bf215546Sopenharmony_ci} catch (error &e) {
126bf215546Sopenharmony_ci   ret_error(r_errcode, e);
127bf215546Sopenharmony_ci   return NULL;
128bf215546Sopenharmony_ci}
129bf215546Sopenharmony_ci
130bf215546Sopenharmony_ci
131bf215546Sopenharmony_ciCLOVER_API cl_mem
132bf215546Sopenharmony_ciclCreateBuffer(cl_context d_ctx, cl_mem_flags d_flags, size_t size,
133bf215546Sopenharmony_ci               void *host_ptr, cl_int *r_errcode) {
134bf215546Sopenharmony_ci   return clCreateBufferWithProperties(d_ctx, NULL, d_flags, size,
135bf215546Sopenharmony_ci                                       host_ptr, r_errcode);
136bf215546Sopenharmony_ci}
137bf215546Sopenharmony_ci
138bf215546Sopenharmony_ciCLOVER_API cl_mem
139bf215546Sopenharmony_ciclCreateSubBuffer(cl_mem d_mem, cl_mem_flags d_flags,
140bf215546Sopenharmony_ci                  cl_buffer_create_type op,
141bf215546Sopenharmony_ci                  const void *op_info, cl_int *r_errcode) try {
142bf215546Sopenharmony_ci   auto &parent = obj<root_buffer>(d_mem);
143bf215546Sopenharmony_ci   const cl_mem_flags flags = validate_flags(d_mem, d_flags, false);
144bf215546Sopenharmony_ci
145bf215546Sopenharmony_ci   if (op == CL_BUFFER_CREATE_TYPE_REGION) {
146bf215546Sopenharmony_ci      auto reg = reinterpret_cast<const cl_buffer_region *>(op_info);
147bf215546Sopenharmony_ci
148bf215546Sopenharmony_ci      if (!reg ||
149bf215546Sopenharmony_ci          reg->origin > parent.size() ||
150bf215546Sopenharmony_ci          reg->origin + reg->size > parent.size())
151bf215546Sopenharmony_ci         throw error(CL_INVALID_VALUE);
152bf215546Sopenharmony_ci
153bf215546Sopenharmony_ci      if (!reg->size)
154bf215546Sopenharmony_ci         throw error(CL_INVALID_BUFFER_SIZE);
155bf215546Sopenharmony_ci
156bf215546Sopenharmony_ci      ret_error(r_errcode, CL_SUCCESS);
157bf215546Sopenharmony_ci      return new sub_buffer(parent, flags, reg->origin, reg->size);
158bf215546Sopenharmony_ci
159bf215546Sopenharmony_ci   } else {
160bf215546Sopenharmony_ci      throw error(CL_INVALID_VALUE);
161bf215546Sopenharmony_ci   }
162bf215546Sopenharmony_ci
163bf215546Sopenharmony_ci} catch (error &e) {
164bf215546Sopenharmony_ci   ret_error(r_errcode, e);
165bf215546Sopenharmony_ci   return NULL;
166bf215546Sopenharmony_ci}
167bf215546Sopenharmony_ci
168bf215546Sopenharmony_ciCLOVER_API cl_mem
169bf215546Sopenharmony_ciclCreateImageWithProperties(cl_context d_ctx,
170bf215546Sopenharmony_ci                            const cl_mem_properties *d_properties,
171bf215546Sopenharmony_ci                            cl_mem_flags d_flags,
172bf215546Sopenharmony_ci                            const cl_image_format *format,
173bf215546Sopenharmony_ci                            const cl_image_desc *desc,
174bf215546Sopenharmony_ci                            void *host_ptr, cl_int *r_errcode) try {
175bf215546Sopenharmony_ci   auto &ctx = obj(d_ctx);
176bf215546Sopenharmony_ci
177bf215546Sopenharmony_ci   if (!any_of(std::mem_fn(&device::image_support), ctx.devices()))
178bf215546Sopenharmony_ci      throw error(CL_INVALID_OPERATION);
179bf215546Sopenharmony_ci
180bf215546Sopenharmony_ci   if (!format)
181bf215546Sopenharmony_ci      throw error(CL_INVALID_IMAGE_FORMAT_DESCRIPTOR);
182bf215546Sopenharmony_ci
183bf215546Sopenharmony_ci   if (!desc)
184bf215546Sopenharmony_ci      throw error(CL_INVALID_IMAGE_DESCRIPTOR);
185bf215546Sopenharmony_ci
186bf215546Sopenharmony_ci   if (desc->image_array_size == 0 &&
187bf215546Sopenharmony_ci       (desc->image_type == CL_MEM_OBJECT_IMAGE1D_ARRAY ||
188bf215546Sopenharmony_ci        desc->image_type == CL_MEM_OBJECT_IMAGE2D_ARRAY))
189bf215546Sopenharmony_ci      throw error(CL_INVALID_IMAGE_DESCRIPTOR);
190bf215546Sopenharmony_ci
191bf215546Sopenharmony_ci   if (!host_ptr &&
192bf215546Sopenharmony_ci       (desc->image_row_pitch || desc->image_slice_pitch))
193bf215546Sopenharmony_ci      throw error(CL_INVALID_IMAGE_DESCRIPTOR);
194bf215546Sopenharmony_ci
195bf215546Sopenharmony_ci   if (desc->num_mip_levels || desc->num_samples)
196bf215546Sopenharmony_ci      throw error(CL_INVALID_IMAGE_DESCRIPTOR);
197bf215546Sopenharmony_ci
198bf215546Sopenharmony_ci   if (bool(desc->buffer) != (desc->image_type == CL_MEM_OBJECT_IMAGE1D_BUFFER))
199bf215546Sopenharmony_ci      throw error(CL_INVALID_IMAGE_DESCRIPTOR);
200bf215546Sopenharmony_ci
201bf215546Sopenharmony_ci   if (bool(host_ptr) != bool(d_flags & (CL_MEM_USE_HOST_PTR |
202bf215546Sopenharmony_ci                                         CL_MEM_COPY_HOST_PTR)))
203bf215546Sopenharmony_ci      throw error(CL_INVALID_HOST_PTR);
204bf215546Sopenharmony_ci
205bf215546Sopenharmony_ci   const cl_mem_flags flags = validate_flags(desc->buffer, d_flags, false);
206bf215546Sopenharmony_ci
207bf215546Sopenharmony_ci   if (!supported_formats(ctx, desc->image_type, d_flags).count(*format))
208bf215546Sopenharmony_ci      throw error(CL_IMAGE_FORMAT_NOT_SUPPORTED);
209bf215546Sopenharmony_ci
210bf215546Sopenharmony_ci   std::vector<cl_mem_properties> properties = fill_properties(d_properties);
211bf215546Sopenharmony_ci   ret_error(r_errcode, CL_SUCCESS);
212bf215546Sopenharmony_ci
213bf215546Sopenharmony_ci   const size_t row_pitch = desc->image_row_pitch ? desc->image_row_pitch :
214bf215546Sopenharmony_ci      util_format_get_blocksize(translate_format(*format)) * desc->image_width;
215bf215546Sopenharmony_ci
216bf215546Sopenharmony_ci   switch (desc->image_type) {
217bf215546Sopenharmony_ci   case CL_MEM_OBJECT_IMAGE1D:
218bf215546Sopenharmony_ci      if (!desc->image_width)
219bf215546Sopenharmony_ci         throw error(CL_INVALID_IMAGE_SIZE);
220bf215546Sopenharmony_ci
221bf215546Sopenharmony_ci      if (all_of([=](const device &dev) {
222bf215546Sopenharmony_ci               const size_t max = dev.max_image_size();
223bf215546Sopenharmony_ci               return (desc->image_width > max);
224bf215546Sopenharmony_ci            }, ctx.devices()))
225bf215546Sopenharmony_ci         throw error(CL_INVALID_IMAGE_SIZE);
226bf215546Sopenharmony_ci
227bf215546Sopenharmony_ci      return new image1d(ctx, properties, flags, format,
228bf215546Sopenharmony_ci                         desc->image_width,
229bf215546Sopenharmony_ci                         row_pitch, host_ptr);
230bf215546Sopenharmony_ci
231bf215546Sopenharmony_ci   case CL_MEM_OBJECT_IMAGE1D_BUFFER:
232bf215546Sopenharmony_ci      if (!desc->image_width)
233bf215546Sopenharmony_ci         throw error(CL_INVALID_IMAGE_SIZE);
234bf215546Sopenharmony_ci
235bf215546Sopenharmony_ci      if (all_of([=](const device &dev) {
236bf215546Sopenharmony_ci               const size_t max = dev.max_image_buffer_size();
237bf215546Sopenharmony_ci               return (desc->image_width > max);
238bf215546Sopenharmony_ci            }, ctx.devices()))
239bf215546Sopenharmony_ci         throw error(CL_INVALID_IMAGE_SIZE);
240bf215546Sopenharmony_ci
241bf215546Sopenharmony_ci      return new image1d_buffer(ctx, properties, flags, format,
242bf215546Sopenharmony_ci                                desc->image_width,
243bf215546Sopenharmony_ci                                row_pitch, host_ptr, desc->buffer);
244bf215546Sopenharmony_ci
245bf215546Sopenharmony_ci   case CL_MEM_OBJECT_IMAGE1D_ARRAY: {
246bf215546Sopenharmony_ci      if (!desc->image_width)
247bf215546Sopenharmony_ci         throw error(CL_INVALID_IMAGE_SIZE);
248bf215546Sopenharmony_ci
249bf215546Sopenharmony_ci      if (all_of([=](const device &dev) {
250bf215546Sopenharmony_ci               const size_t max = dev.max_image_size();
251bf215546Sopenharmony_ci               const size_t amax = dev.max_image_array_number();
252bf215546Sopenharmony_ci               return (desc->image_width > max ||
253bf215546Sopenharmony_ci                       desc->image_array_size > amax);
254bf215546Sopenharmony_ci            }, ctx.devices()))
255bf215546Sopenharmony_ci         throw error(CL_INVALID_IMAGE_SIZE);
256bf215546Sopenharmony_ci
257bf215546Sopenharmony_ci      const size_t slice_pitch = desc->image_slice_pitch ?
258bf215546Sopenharmony_ci         desc->image_slice_pitch : row_pitch;
259bf215546Sopenharmony_ci
260bf215546Sopenharmony_ci      return new image1d_array(ctx, properties, flags, format,
261bf215546Sopenharmony_ci                               desc->image_width,
262bf215546Sopenharmony_ci                               desc->image_array_size, slice_pitch,
263bf215546Sopenharmony_ci                               host_ptr);
264bf215546Sopenharmony_ci   }
265bf215546Sopenharmony_ci
266bf215546Sopenharmony_ci   case CL_MEM_OBJECT_IMAGE2D:
267bf215546Sopenharmony_ci      if (!desc->image_width || !desc->image_height)
268bf215546Sopenharmony_ci         throw error(CL_INVALID_IMAGE_SIZE);
269bf215546Sopenharmony_ci
270bf215546Sopenharmony_ci      if (all_of([=](const device &dev) {
271bf215546Sopenharmony_ci               const size_t max = dev.max_image_size();
272bf215546Sopenharmony_ci               return (desc->image_width > max ||
273bf215546Sopenharmony_ci                       desc->image_height > max);
274bf215546Sopenharmony_ci            }, ctx.devices()))
275bf215546Sopenharmony_ci         throw error(CL_INVALID_IMAGE_SIZE);
276bf215546Sopenharmony_ci
277bf215546Sopenharmony_ci      return new image2d(ctx, properties, flags, format,
278bf215546Sopenharmony_ci                         desc->image_width, desc->image_height,
279bf215546Sopenharmony_ci                         row_pitch, host_ptr);
280bf215546Sopenharmony_ci
281bf215546Sopenharmony_ci   case CL_MEM_OBJECT_IMAGE2D_ARRAY: {
282bf215546Sopenharmony_ci      if (!desc->image_width || !desc->image_height || !desc->image_array_size)
283bf215546Sopenharmony_ci         throw error(CL_INVALID_IMAGE_SIZE);
284bf215546Sopenharmony_ci
285bf215546Sopenharmony_ci      if (all_of([=](const device &dev) {
286bf215546Sopenharmony_ci               const size_t max = dev.max_image_size();
287bf215546Sopenharmony_ci               const size_t amax = dev.max_image_array_number();
288bf215546Sopenharmony_ci               return (desc->image_width > max ||
289bf215546Sopenharmony_ci                       desc->image_height > max ||
290bf215546Sopenharmony_ci                       desc->image_array_size > amax);
291bf215546Sopenharmony_ci            }, ctx.devices()))
292bf215546Sopenharmony_ci         throw error(CL_INVALID_IMAGE_SIZE);
293bf215546Sopenharmony_ci
294bf215546Sopenharmony_ci      const size_t slice_pitch = desc->image_slice_pitch ?
295bf215546Sopenharmony_ci         desc->image_slice_pitch : row_pitch * desc->image_height;
296bf215546Sopenharmony_ci
297bf215546Sopenharmony_ci      return new image2d_array(ctx, properties, flags, format,
298bf215546Sopenharmony_ci                               desc->image_width, desc->image_height,
299bf215546Sopenharmony_ci                               desc->image_array_size, row_pitch,
300bf215546Sopenharmony_ci                               slice_pitch, host_ptr);
301bf215546Sopenharmony_ci   }
302bf215546Sopenharmony_ci
303bf215546Sopenharmony_ci   case CL_MEM_OBJECT_IMAGE3D: {
304bf215546Sopenharmony_ci      if (!desc->image_width || !desc->image_height || !desc->image_depth)
305bf215546Sopenharmony_ci         throw error(CL_INVALID_IMAGE_SIZE);
306bf215546Sopenharmony_ci
307bf215546Sopenharmony_ci      if (all_of([=](const device &dev) {
308bf215546Sopenharmony_ci               const size_t max = dev.max_image_size_3d();
309bf215546Sopenharmony_ci               return (desc->image_width > max ||
310bf215546Sopenharmony_ci                       desc->image_height > max ||
311bf215546Sopenharmony_ci                       desc->image_depth > max);
312bf215546Sopenharmony_ci            }, ctx.devices()))
313bf215546Sopenharmony_ci         throw error(CL_INVALID_IMAGE_SIZE);
314bf215546Sopenharmony_ci
315bf215546Sopenharmony_ci      const size_t slice_pitch = desc->image_slice_pitch ?
316bf215546Sopenharmony_ci         desc->image_slice_pitch : row_pitch * desc->image_height;
317bf215546Sopenharmony_ci
318bf215546Sopenharmony_ci      return new image3d(ctx, properties, flags, format,
319bf215546Sopenharmony_ci                         desc->image_width, desc->image_height,
320bf215546Sopenharmony_ci                         desc->image_depth, row_pitch,
321bf215546Sopenharmony_ci                         slice_pitch, host_ptr);
322bf215546Sopenharmony_ci   }
323bf215546Sopenharmony_ci
324bf215546Sopenharmony_ci   default:
325bf215546Sopenharmony_ci      throw error(CL_INVALID_IMAGE_DESCRIPTOR);
326bf215546Sopenharmony_ci   }
327bf215546Sopenharmony_ci
328bf215546Sopenharmony_ci} catch (error &e) {
329bf215546Sopenharmony_ci   ret_error(r_errcode, e);
330bf215546Sopenharmony_ci   return NULL;
331bf215546Sopenharmony_ci}
332bf215546Sopenharmony_ci
333bf215546Sopenharmony_ciCLOVER_API cl_mem
334bf215546Sopenharmony_ciclCreateImage(cl_context d_ctx,
335bf215546Sopenharmony_ci              cl_mem_flags d_flags,
336bf215546Sopenharmony_ci              const cl_image_format *format,
337bf215546Sopenharmony_ci              const cl_image_desc *desc,
338bf215546Sopenharmony_ci              void *host_ptr, cl_int *r_errcode) {
339bf215546Sopenharmony_ci   return clCreateImageWithProperties(d_ctx, NULL, d_flags, format, desc, host_ptr, r_errcode);
340bf215546Sopenharmony_ci}
341bf215546Sopenharmony_ci
342bf215546Sopenharmony_ci
343bf215546Sopenharmony_ciCLOVER_API cl_mem
344bf215546Sopenharmony_ciclCreateImage2D(cl_context d_ctx, cl_mem_flags d_flags,
345bf215546Sopenharmony_ci                const cl_image_format *format,
346bf215546Sopenharmony_ci                size_t width, size_t height, size_t row_pitch,
347bf215546Sopenharmony_ci                void *host_ptr, cl_int *r_errcode) {
348bf215546Sopenharmony_ci   const cl_image_desc desc = { CL_MEM_OBJECT_IMAGE2D, width, height, 0, 0,
349bf215546Sopenharmony_ci                                row_pitch, 0, 0, 0, NULL };
350bf215546Sopenharmony_ci
351bf215546Sopenharmony_ci   return clCreateImageWithProperties(d_ctx, NULL, d_flags, format, &desc, host_ptr, r_errcode);
352bf215546Sopenharmony_ci}
353bf215546Sopenharmony_ci
354bf215546Sopenharmony_ciCLOVER_API cl_mem
355bf215546Sopenharmony_ciclCreateImage3D(cl_context d_ctx, cl_mem_flags d_flags,
356bf215546Sopenharmony_ci                const cl_image_format *format,
357bf215546Sopenharmony_ci                size_t width, size_t height, size_t depth,
358bf215546Sopenharmony_ci                size_t row_pitch, size_t slice_pitch,
359bf215546Sopenharmony_ci                void *host_ptr, cl_int *r_errcode) {
360bf215546Sopenharmony_ci   const cl_image_desc desc = { CL_MEM_OBJECT_IMAGE3D, width, height, depth, 0,
361bf215546Sopenharmony_ci                                row_pitch, slice_pitch, 0, 0, NULL };
362bf215546Sopenharmony_ci
363bf215546Sopenharmony_ci   return clCreateImageWithProperties(d_ctx, NULL, d_flags, format, &desc, host_ptr, r_errcode);
364bf215546Sopenharmony_ci}
365bf215546Sopenharmony_ci
366bf215546Sopenharmony_ciCLOVER_API cl_int
367bf215546Sopenharmony_ciclGetSupportedImageFormats(cl_context d_ctx, cl_mem_flags flags,
368bf215546Sopenharmony_ci                           cl_mem_object_type type, cl_uint count,
369bf215546Sopenharmony_ci                           cl_image_format *r_buf, cl_uint *r_count) try {
370bf215546Sopenharmony_ci   auto &ctx = obj(d_ctx);
371bf215546Sopenharmony_ci   auto formats = supported_formats(ctx, type, flags);
372bf215546Sopenharmony_ci
373bf215546Sopenharmony_ci   if (flags & CL_MEM_KERNEL_READ_AND_WRITE) {
374bf215546Sopenharmony_ci      if (r_count)
375bf215546Sopenharmony_ci         *r_count = 0;
376bf215546Sopenharmony_ci      return CL_SUCCESS;
377bf215546Sopenharmony_ci   }
378bf215546Sopenharmony_ci
379bf215546Sopenharmony_ci   if (flags & (CL_MEM_WRITE_ONLY | CL_MEM_READ_WRITE) &&
380bf215546Sopenharmony_ci       type == CL_MEM_OBJECT_IMAGE3D) {
381bf215546Sopenharmony_ci      if (r_count)
382bf215546Sopenharmony_ci         *r_count = 0;
383bf215546Sopenharmony_ci      return CL_SUCCESS;
384bf215546Sopenharmony_ci   }
385bf215546Sopenharmony_ci
386bf215546Sopenharmony_ci   validate_flags(NULL, flags, false);
387bf215546Sopenharmony_ci
388bf215546Sopenharmony_ci   if (r_buf && !count)
389bf215546Sopenharmony_ci      throw error(CL_INVALID_VALUE);
390bf215546Sopenharmony_ci
391bf215546Sopenharmony_ci   if (r_buf)
392bf215546Sopenharmony_ci      std::copy_n(formats.begin(),
393bf215546Sopenharmony_ci                  std::min((cl_uint)formats.size(), count),
394bf215546Sopenharmony_ci                  r_buf);
395bf215546Sopenharmony_ci
396bf215546Sopenharmony_ci   if (r_count)
397bf215546Sopenharmony_ci      *r_count = formats.size();
398bf215546Sopenharmony_ci
399bf215546Sopenharmony_ci   return CL_SUCCESS;
400bf215546Sopenharmony_ci
401bf215546Sopenharmony_ci} catch (error &e) {
402bf215546Sopenharmony_ci   return e.get();
403bf215546Sopenharmony_ci}
404bf215546Sopenharmony_ci
405bf215546Sopenharmony_ciCLOVER_API cl_int
406bf215546Sopenharmony_ciclGetMemObjectInfo(cl_mem d_mem, cl_mem_info param,
407bf215546Sopenharmony_ci                   size_t size, void *r_buf, size_t *r_size) try {
408bf215546Sopenharmony_ci   property_buffer buf { r_buf, size, r_size };
409bf215546Sopenharmony_ci   auto &mem = obj(d_mem);
410bf215546Sopenharmony_ci
411bf215546Sopenharmony_ci   switch (param) {
412bf215546Sopenharmony_ci   case CL_MEM_TYPE:
413bf215546Sopenharmony_ci      buf.as_scalar<cl_mem_object_type>() = mem.type();
414bf215546Sopenharmony_ci      break;
415bf215546Sopenharmony_ci
416bf215546Sopenharmony_ci   case CL_MEM_FLAGS:
417bf215546Sopenharmony_ci      buf.as_scalar<cl_mem_flags>() = mem.flags();
418bf215546Sopenharmony_ci      break;
419bf215546Sopenharmony_ci
420bf215546Sopenharmony_ci   case CL_MEM_SIZE:
421bf215546Sopenharmony_ci      buf.as_scalar<size_t>() = mem.size();
422bf215546Sopenharmony_ci      break;
423bf215546Sopenharmony_ci
424bf215546Sopenharmony_ci   case CL_MEM_HOST_PTR:
425bf215546Sopenharmony_ci      buf.as_scalar<void *>() = mem.host_ptr();
426bf215546Sopenharmony_ci      break;
427bf215546Sopenharmony_ci
428bf215546Sopenharmony_ci   case CL_MEM_MAP_COUNT:
429bf215546Sopenharmony_ci      buf.as_scalar<cl_uint>() = 0;
430bf215546Sopenharmony_ci      break;
431bf215546Sopenharmony_ci
432bf215546Sopenharmony_ci   case CL_MEM_REFERENCE_COUNT:
433bf215546Sopenharmony_ci      buf.as_scalar<cl_uint>() = mem.ref_count();
434bf215546Sopenharmony_ci      break;
435bf215546Sopenharmony_ci
436bf215546Sopenharmony_ci   case CL_MEM_CONTEXT:
437bf215546Sopenharmony_ci      buf.as_scalar<cl_context>() = desc(mem.context());
438bf215546Sopenharmony_ci      break;
439bf215546Sopenharmony_ci
440bf215546Sopenharmony_ci   case CL_MEM_ASSOCIATED_MEMOBJECT: {
441bf215546Sopenharmony_ci      sub_buffer *sub = dynamic_cast<sub_buffer *>(&mem);
442bf215546Sopenharmony_ci      if (sub) {
443bf215546Sopenharmony_ci         buf.as_scalar<cl_mem>() = desc(sub->parent());
444bf215546Sopenharmony_ci         break;
445bf215546Sopenharmony_ci      }
446bf215546Sopenharmony_ci
447bf215546Sopenharmony_ci      image *img = dynamic_cast<image *>(&mem);
448bf215546Sopenharmony_ci      if (img) {
449bf215546Sopenharmony_ci         buf.as_scalar<cl_mem>() = desc(img->buffer());
450bf215546Sopenharmony_ci         break;
451bf215546Sopenharmony_ci      }
452bf215546Sopenharmony_ci
453bf215546Sopenharmony_ci      buf.as_scalar<cl_mem>() = NULL;
454bf215546Sopenharmony_ci      break;
455bf215546Sopenharmony_ci   }
456bf215546Sopenharmony_ci   case CL_MEM_OFFSET: {
457bf215546Sopenharmony_ci      sub_buffer *sub = dynamic_cast<sub_buffer *>(&mem);
458bf215546Sopenharmony_ci      buf.as_scalar<size_t>() = (sub ? sub->offset() : 0);
459bf215546Sopenharmony_ci      break;
460bf215546Sopenharmony_ci   }
461bf215546Sopenharmony_ci   case CL_MEM_USES_SVM_POINTER:
462bf215546Sopenharmony_ci   case CL_MEM_USES_SVM_POINTER_ARM: {
463bf215546Sopenharmony_ci      // with system SVM all host ptrs are SVM pointers
464bf215546Sopenharmony_ci      // TODO: once we support devices with lower levels of SVM, we have to
465bf215546Sopenharmony_ci      // check the ptr in more detail
466bf215546Sopenharmony_ci      const bool system_svm = all_of(std::mem_fn(&device::has_system_svm),
467bf215546Sopenharmony_ci                                     mem.context().devices());
468bf215546Sopenharmony_ci      buf.as_scalar<cl_bool>() = mem.host_ptr() && system_svm;
469bf215546Sopenharmony_ci      break;
470bf215546Sopenharmony_ci   }
471bf215546Sopenharmony_ci   case CL_MEM_PROPERTIES:
472bf215546Sopenharmony_ci      buf.as_vector<cl_mem_properties>() = mem.properties();
473bf215546Sopenharmony_ci      break;
474bf215546Sopenharmony_ci   default:
475bf215546Sopenharmony_ci      throw error(CL_INVALID_VALUE);
476bf215546Sopenharmony_ci   }
477bf215546Sopenharmony_ci
478bf215546Sopenharmony_ci   return CL_SUCCESS;
479bf215546Sopenharmony_ci
480bf215546Sopenharmony_ci} catch (error &e) {
481bf215546Sopenharmony_ci   return e.get();
482bf215546Sopenharmony_ci}
483bf215546Sopenharmony_ci
484bf215546Sopenharmony_ciCLOVER_API cl_int
485bf215546Sopenharmony_ciclGetImageInfo(cl_mem d_mem, cl_image_info param,
486bf215546Sopenharmony_ci               size_t size, void *r_buf, size_t *r_size) try {
487bf215546Sopenharmony_ci   property_buffer buf { r_buf, size, r_size };
488bf215546Sopenharmony_ci   auto &img = obj<image>(d_mem);
489bf215546Sopenharmony_ci
490bf215546Sopenharmony_ci   switch (param) {
491bf215546Sopenharmony_ci   case CL_IMAGE_FORMAT:
492bf215546Sopenharmony_ci      buf.as_scalar<cl_image_format>() = img.format();
493bf215546Sopenharmony_ci      break;
494bf215546Sopenharmony_ci
495bf215546Sopenharmony_ci   case CL_IMAGE_ELEMENT_SIZE:
496bf215546Sopenharmony_ci      buf.as_scalar<size_t>() = img.pixel_size();
497bf215546Sopenharmony_ci      break;
498bf215546Sopenharmony_ci
499bf215546Sopenharmony_ci   case CL_IMAGE_ROW_PITCH:
500bf215546Sopenharmony_ci      buf.as_scalar<size_t>() = img.row_pitch();
501bf215546Sopenharmony_ci      break;
502bf215546Sopenharmony_ci
503bf215546Sopenharmony_ci   case CL_IMAGE_SLICE_PITCH:
504bf215546Sopenharmony_ci      buf.as_scalar<size_t>() = img.slice_pitch();
505bf215546Sopenharmony_ci      break;
506bf215546Sopenharmony_ci
507bf215546Sopenharmony_ci   case CL_IMAGE_WIDTH:
508bf215546Sopenharmony_ci      buf.as_scalar<size_t>() = img.width();
509bf215546Sopenharmony_ci      break;
510bf215546Sopenharmony_ci
511bf215546Sopenharmony_ci   case CL_IMAGE_HEIGHT:
512bf215546Sopenharmony_ci      buf.as_scalar<size_t>() = img.dimensions() > 1 ? img.height() : 0;
513bf215546Sopenharmony_ci      break;
514bf215546Sopenharmony_ci
515bf215546Sopenharmony_ci   case CL_IMAGE_DEPTH:
516bf215546Sopenharmony_ci      buf.as_scalar<size_t>() = img.dimensions() > 2 ? img.depth() : 0;
517bf215546Sopenharmony_ci      break;
518bf215546Sopenharmony_ci
519bf215546Sopenharmony_ci   case CL_IMAGE_ARRAY_SIZE:
520bf215546Sopenharmony_ci      buf.as_scalar<size_t>() = img.array_size();
521bf215546Sopenharmony_ci      break;
522bf215546Sopenharmony_ci
523bf215546Sopenharmony_ci   case CL_IMAGE_BUFFER:
524bf215546Sopenharmony_ci      buf.as_scalar<cl_mem>() = img.buffer();
525bf215546Sopenharmony_ci      break;
526bf215546Sopenharmony_ci
527bf215546Sopenharmony_ci   case CL_IMAGE_NUM_MIP_LEVELS:
528bf215546Sopenharmony_ci      buf.as_scalar<cl_uint>() = 0;
529bf215546Sopenharmony_ci      break;
530bf215546Sopenharmony_ci
531bf215546Sopenharmony_ci   case CL_IMAGE_NUM_SAMPLES:
532bf215546Sopenharmony_ci      buf.as_scalar<cl_uint>() = 0;
533bf215546Sopenharmony_ci      break;
534bf215546Sopenharmony_ci
535bf215546Sopenharmony_ci   default:
536bf215546Sopenharmony_ci      throw error(CL_INVALID_VALUE);
537bf215546Sopenharmony_ci   }
538bf215546Sopenharmony_ci
539bf215546Sopenharmony_ci   return CL_SUCCESS;
540bf215546Sopenharmony_ci
541bf215546Sopenharmony_ci} catch (error &e) {
542bf215546Sopenharmony_ci   return e.get();
543bf215546Sopenharmony_ci}
544bf215546Sopenharmony_ci
545bf215546Sopenharmony_ciCLOVER_API cl_int
546bf215546Sopenharmony_ciclRetainMemObject(cl_mem d_mem) try {
547bf215546Sopenharmony_ci   obj(d_mem).retain();
548bf215546Sopenharmony_ci   return CL_SUCCESS;
549bf215546Sopenharmony_ci
550bf215546Sopenharmony_ci} catch (error &e) {
551bf215546Sopenharmony_ci   return e.get();
552bf215546Sopenharmony_ci}
553bf215546Sopenharmony_ci
554bf215546Sopenharmony_ciCLOVER_API cl_int
555bf215546Sopenharmony_ciclReleaseMemObject(cl_mem d_mem) try {
556bf215546Sopenharmony_ci   if (obj(d_mem).release())
557bf215546Sopenharmony_ci      delete pobj(d_mem);
558bf215546Sopenharmony_ci
559bf215546Sopenharmony_ci   return CL_SUCCESS;
560bf215546Sopenharmony_ci
561bf215546Sopenharmony_ci} catch (error &e) {
562bf215546Sopenharmony_ci   return e.get();
563bf215546Sopenharmony_ci}
564bf215546Sopenharmony_ci
565bf215546Sopenharmony_ciCLOVER_API cl_int
566bf215546Sopenharmony_ciclSetMemObjectDestructorCallback(cl_mem d_mem,
567bf215546Sopenharmony_ci                                 void (CL_CALLBACK *pfn_notify)(cl_mem, void *),
568bf215546Sopenharmony_ci                                 void *user_data) try {
569bf215546Sopenharmony_ci   auto &mem = obj(d_mem);
570bf215546Sopenharmony_ci
571bf215546Sopenharmony_ci   if (!pfn_notify)
572bf215546Sopenharmony_ci      return CL_INVALID_VALUE;
573bf215546Sopenharmony_ci
574bf215546Sopenharmony_ci   mem.destroy_notify([=]{ pfn_notify(d_mem, user_data); });
575bf215546Sopenharmony_ci
576bf215546Sopenharmony_ci   return CL_SUCCESS;
577bf215546Sopenharmony_ci
578bf215546Sopenharmony_ci} catch (error &e) {
579bf215546Sopenharmony_ci   return e.get();
580bf215546Sopenharmony_ci}
581bf215546Sopenharmony_ci
582bf215546Sopenharmony_ciCLOVER_API void *
583bf215546Sopenharmony_ciclSVMAlloc(cl_context d_ctx,
584bf215546Sopenharmony_ci           cl_svm_mem_flags flags,
585bf215546Sopenharmony_ci           size_t size,
586bf215546Sopenharmony_ci           unsigned int alignment) try {
587bf215546Sopenharmony_ci   auto &ctx = obj(d_ctx);
588bf215546Sopenharmony_ci
589bf215546Sopenharmony_ci   if (!any_of(std::mem_fn(&device::svm_support), ctx.devices()))
590bf215546Sopenharmony_ci      return NULL;
591bf215546Sopenharmony_ci
592bf215546Sopenharmony_ci   validate_flags(NULL, flags, true);
593bf215546Sopenharmony_ci
594bf215546Sopenharmony_ci   if (!size ||
595bf215546Sopenharmony_ci       size > fold(minimum(), cl_ulong(ULONG_MAX),
596bf215546Sopenharmony_ci                   map(std::mem_fn(&device::max_mem_alloc_size), ctx.devices())))
597bf215546Sopenharmony_ci      return nullptr;
598bf215546Sopenharmony_ci
599bf215546Sopenharmony_ci   if (!util_is_power_of_two_or_zero(alignment))
600bf215546Sopenharmony_ci      return nullptr;
601bf215546Sopenharmony_ci
602bf215546Sopenharmony_ci   if (!alignment)
603bf215546Sopenharmony_ci      alignment = 0x80; // sizeof(long16)
604bf215546Sopenharmony_ci
605bf215546Sopenharmony_ci#if HAVE_POSIX_MEMALIGN
606bf215546Sopenharmony_ci   bool can_emulate = all_of(std::mem_fn(&device::has_system_svm), ctx.devices());
607bf215546Sopenharmony_ci   if (can_emulate) {
608bf215546Sopenharmony_ci      // we can ignore all the flags as it's not required to honor them.
609bf215546Sopenharmony_ci      void *ptr = nullptr;
610bf215546Sopenharmony_ci      if (alignment < sizeof(void*))
611bf215546Sopenharmony_ci         alignment = sizeof(void*);
612bf215546Sopenharmony_ci      posix_memalign(&ptr, alignment, size);
613bf215546Sopenharmony_ci
614bf215546Sopenharmony_ci      if (ptr)
615bf215546Sopenharmony_ci         ctx.add_svm_allocation(ptr, size);
616bf215546Sopenharmony_ci
617bf215546Sopenharmony_ci      return ptr;
618bf215546Sopenharmony_ci   }
619bf215546Sopenharmony_ci#endif
620bf215546Sopenharmony_ci
621bf215546Sopenharmony_ci   CLOVER_NOT_SUPPORTED_UNTIL("2.0");
622bf215546Sopenharmony_ci   return nullptr;
623bf215546Sopenharmony_ci
624bf215546Sopenharmony_ci} catch (error &) {
625bf215546Sopenharmony_ci   return nullptr;
626bf215546Sopenharmony_ci}
627bf215546Sopenharmony_ci
628bf215546Sopenharmony_ciCLOVER_API void
629bf215546Sopenharmony_ciclSVMFree(cl_context d_ctx,
630bf215546Sopenharmony_ci          void *svm_pointer) try {
631bf215546Sopenharmony_ci   auto &ctx = obj(d_ctx);
632bf215546Sopenharmony_ci
633bf215546Sopenharmony_ci   if (!any_of(std::mem_fn(&device::svm_support), ctx.devices()))
634bf215546Sopenharmony_ci      return;
635bf215546Sopenharmony_ci
636bf215546Sopenharmony_ci   bool can_emulate = all_of(std::mem_fn(&device::has_system_svm), ctx.devices());
637bf215546Sopenharmony_ci
638bf215546Sopenharmony_ci   if (can_emulate) {
639bf215546Sopenharmony_ci      ctx.remove_svm_allocation(svm_pointer);
640bf215546Sopenharmony_ci      return free(svm_pointer);
641bf215546Sopenharmony_ci   }
642bf215546Sopenharmony_ci
643bf215546Sopenharmony_ci   CLOVER_NOT_SUPPORTED_UNTIL("2.0");
644bf215546Sopenharmony_ci
645bf215546Sopenharmony_ci} catch (error &) {
646bf215546Sopenharmony_ci}
647