return range(p, 3);
}
+ vector_t
+ pitch(const vector_t ®ion, vector_t pitch) {
+ for (auto x : zip(tail(pitch),
+ map(multiplies(), region, pitch))) {
+ // The spec defines a value of zero as the natural pitch,
+ // i.e. the unaligned size of the previous dimension.
+ if (std::get<0>(x) == 0)
+ std::get<0>(x) = std::get<1>(x);
+ }
+
+ return pitch;
+ }
+
///
/// Common argument checking shared by memory transfer commands.
///
void
validate_common(command_queue &q,
- std::initializer_list<std::reference_wrapper<memory_obj>> mems,
const ref_vector<event> &deps) {
if (any_of([&](const event &ev) {
return &ev.ctx != &q.ctx;
}, deps))
throw error(CL_INVALID_CONTEXT);
+ }
- if (any_of([&](const memory_obj &mem) {
- return &mem.ctx != &q.ctx;
- }, mems))
+ ///
+ /// Common error checking for a buffer object argument.
+ ///
+ void
+ validate_object(command_queue &q, buffer &mem, const vector_t &origin,
+ const vector_t &pitch, const vector_t ®ion) {
+ if (mem.ctx != q.ctx)
throw error(CL_INVALID_CONTEXT);
+
+ // The region must fit within the specified pitch,
+ if (any_of(greater(), map(multiplies(), pitch, region), tail(pitch)))
+ throw error(CL_INVALID_VALUE);
+
+ // ...and within the specified object.
+ if (dot(pitch, origin) + pitch[2] * region[2] > mem.size())
+ throw error(CL_INVALID_VALUE);
+
+ if (any_of(is_zero(), region))
+ throw error(CL_INVALID_VALUE);
+ }
+
+ ///
+ /// Common error checking for an image argument.
+ ///
+ void
+ validate_object(command_queue &q, image &img,
+ const vector_t &orig, const vector_t ®ion) {
+ vector_t size = { img.width(), img.height(), img.depth() };
+
+ if (img.ctx != q.ctx)
+ throw error(CL_INVALID_CONTEXT);
+
+ if (any_of(greater(), orig + region, size))
+ throw error(CL_INVALID_VALUE);
+
+ if (any_of(is_zero(), region))
+ throw error(CL_INVALID_VALUE);
+ }
+
+ ///
+ /// Common error checking for a host pointer argument.
+ ///
+ void
+ validate_object(command_queue &q, const void *ptr, const vector_t &orig,
+ const vector_t &pitch, const vector_t ®ion) {
+ if (!ptr)
+ throw error(CL_INVALID_VALUE);
+
+ // The region must fit within the specified pitch.
+ if (any_of(greater(), map(multiplies(), pitch, region), tail(pitch)))
+ throw error(CL_INVALID_VALUE);
+ }
+
+ ///
+ /// Common argument checking for a copy between two buffer objects.
+ ///
+ void
+ validate_copy(command_queue &q, buffer &dst_mem,
+ const vector_t &dst_orig, const vector_t &dst_pitch,
+ buffer &src_mem,
+ const vector_t &src_orig, const vector_t &src_pitch,
+ const vector_t ®ion) {
+ if (dst_mem == src_mem) {
+ auto dst_offset = dot(dst_pitch, dst_orig);
+ auto src_offset = dot(src_pitch, src_orig);
+
+ if (interval_overlaps()(
+ dst_offset, dst_offset + dst_pitch[2] * region[2],
+ src_offset, src_offset + src_pitch[2] * region[2]))
+ throw error(CL_MEM_COPY_OVERLAP);
+ }
+ }
+
+ ///
+ /// Common argument checking for a copy between two image objects.
+ ///
+ void
+ validate_copy(command_queue &q,
+ image &dst_img, const vector_t &dst_orig,
+ image &src_img, const vector_t &src_orig,
+ const vector_t ®ion) {
+ if (dst_img.format() != src_img.format())
+ throw error(CL_IMAGE_FORMAT_MISMATCH);
+
+ if (dst_img == src_img) {
+ if (all_of(interval_overlaps(),
+ dst_orig, dst_orig + region,
+ src_orig, src_orig + region))
+ throw error(CL_MEM_COPY_OVERLAP);
+ }
}
///
cl_uint num_deps, const cl_event *d_deps,
cl_event *rd_ev) try {
auto &q = obj(d_q);
- auto &mem = obj(d_mem);
+ auto &mem = obj<buffer>(d_mem);
auto deps = objs<wait_list_tag>(d_deps, num_deps);
+ vector_t region = { size, 1, 1 };
+ vector_t obj_origin = { offset };
+ auto obj_pitch = pitch(region, {{ 1 }});
- validate_common(q, { mem }, deps);
-
- if (!ptr || offset > mem.size() || offset + size > mem.size())
- throw error(CL_INVALID_VALUE);
+ validate_common(q, deps);
+ validate_object(q, ptr, {}, obj_pitch, region);
+ validate_object(q, mem, obj_origin, obj_pitch, region);
hard_event *hev = new hard_event(
q, CL_COMMAND_READ_BUFFER, deps,
- soft_copy_op(q,
- ptr, {{ 0 }}, {{ 1 }},
- &mem, {{ offset }}, {{ 1 }},
- {{ size, 1, 1 }}));
+ soft_copy_op(q, ptr, {}, obj_pitch,
+ &mem, obj_origin, obj_pitch,
+ region));
ret_object(rd_ev, hev);
return CL_SUCCESS;
cl_uint num_deps, const cl_event *d_deps,
cl_event *rd_ev) try {
auto &q = obj(d_q);
- auto &mem = obj(d_mem);
+ auto &mem = obj<buffer>(d_mem);
auto deps = objs<wait_list_tag>(d_deps, num_deps);
+ vector_t region = { size, 1, 1 };
+ vector_t obj_origin = { offset };
+ auto obj_pitch = pitch(region, {{ 1 }});
- validate_common(q, { mem }, deps);
-
- if (!ptr || offset > mem.size() || offset + size > mem.size())
- throw error(CL_INVALID_VALUE);
+ validate_common(q, deps);
+ validate_object(q, mem, obj_origin, obj_pitch, region);
+ validate_object(q, ptr, {}, obj_pitch, region);
hard_event *hev = new hard_event(
q, CL_COMMAND_WRITE_BUFFER, deps,
- soft_copy_op(q,
- &mem, {{ offset }}, {{ 1 }},
- ptr, {{ 0 }}, {{ 1 }},
- {{ size, 1, 1 }}));
+ soft_copy_op(q, &mem, obj_origin, obj_pitch,
+ ptr, {}, obj_pitch,
+ region));
ret_object(rd_ev, hev);
return CL_SUCCESS;
CLOVER_API cl_int
clEnqueueReadBufferRect(cl_command_queue d_q, cl_mem d_mem, cl_bool blocking,
- const size_t *obj_origin,
- const size_t *host_origin,
- const size_t *region,
+ const size_t *p_obj_origin,
+ const size_t *p_host_origin,
+ const size_t *p_region,
size_t obj_row_pitch, size_t obj_slice_pitch,
size_t host_row_pitch, size_t host_slice_pitch,
void *ptr,
cl_uint num_deps, const cl_event *d_deps,
cl_event *rd_ev) try {
auto &q = obj(d_q);
- auto &mem = obj(d_mem);
+ auto &mem = obj<buffer>(d_mem);
auto deps = objs<wait_list_tag>(d_deps, num_deps);
+ auto region = vector(p_region);
+ auto obj_origin = vector(p_obj_origin);
+ auto obj_pitch = pitch(region, {{ 1, obj_row_pitch, obj_slice_pitch }});
+ auto host_origin = vector(p_host_origin);
+ auto host_pitch = pitch(region, {{ 1, host_row_pitch, host_slice_pitch }});
- validate_common(q, { mem }, deps);
-
- if (!ptr)
- throw error(CL_INVALID_VALUE);
+ validate_common(q, deps);
+ validate_object(q, ptr, host_origin, host_pitch, region);
+ validate_object(q, mem, obj_origin, obj_pitch, region);
hard_event *hev = new hard_event(
q, CL_COMMAND_READ_BUFFER_RECT, deps,
- soft_copy_op(q,
- ptr, vector(host_origin),
- {{ 1, host_row_pitch, host_slice_pitch }},
- &mem, vector(obj_origin),
- {{ 1, obj_row_pitch, obj_slice_pitch }},
- vector(region)));
+ soft_copy_op(q, ptr, host_origin, host_pitch,
+ &mem, obj_origin, obj_pitch,
+ region));
ret_object(rd_ev, hev);
return CL_SUCCESS;
CLOVER_API cl_int
clEnqueueWriteBufferRect(cl_command_queue d_q, cl_mem d_mem, cl_bool blocking,
- const size_t *obj_origin,
- const size_t *host_origin,
- const size_t *region,
+ const size_t *p_obj_origin,
+ const size_t *p_host_origin,
+ const size_t *p_region,
size_t obj_row_pitch, size_t obj_slice_pitch,
size_t host_row_pitch, size_t host_slice_pitch,
const void *ptr,
cl_uint num_deps, const cl_event *d_deps,
cl_event *rd_ev) try {
auto &q = obj(d_q);
- auto &mem = obj(d_mem);
+ auto &mem = obj<buffer>(d_mem);
auto deps = objs<wait_list_tag>(d_deps, num_deps);
+ auto region = vector(p_region);
+ auto obj_origin = vector(p_obj_origin);
+ auto obj_pitch = pitch(region, {{ 1, obj_row_pitch, obj_slice_pitch }});
+ auto host_origin = vector(p_host_origin);
+ auto host_pitch = pitch(region, {{ 1, host_row_pitch, host_slice_pitch }});
- validate_common(q, { mem }, deps);
-
- if (!ptr)
- throw error(CL_INVALID_VALUE);
+ validate_common(q, deps);
+ validate_object(q, mem, obj_origin, obj_pitch, region);
+ validate_object(q, ptr, host_origin, host_pitch, region);
hard_event *hev = new hard_event(
q, CL_COMMAND_WRITE_BUFFER_RECT, deps,
- soft_copy_op(q,
- &mem, vector(obj_origin),
- {{ 1, obj_row_pitch, obj_slice_pitch }},
- ptr, vector(host_origin),
- {{ 1, host_row_pitch, host_slice_pitch }},
- vector(region)));
+ soft_copy_op(q, &mem, obj_origin, obj_pitch,
+ ptr, host_origin, host_pitch,
+ region));
ret_object(rd_ev, hev);
return CL_SUCCESS;
cl_uint num_deps, const cl_event *d_deps,
cl_event *rd_ev) try {
auto &q = obj(d_q);
- auto &src_mem = obj(d_src_mem);
- auto &dst_mem = obj(d_dst_mem);
+ auto &src_mem = obj<buffer>(d_src_mem);
+ auto &dst_mem = obj<buffer>(d_dst_mem);
auto deps = objs<wait_list_tag>(d_deps, num_deps);
-
- validate_common(q, { src_mem, dst_mem }, deps);
+ vector_t region = { size, 1, 1 };
+ vector_t dst_origin = { dst_offset };
+ auto dst_pitch = pitch(region, {{ 1 }});
+ vector_t src_origin = { src_offset };
+ auto src_pitch = pitch(region, {{ 1 }});
+
+ validate_common(q, deps);
+ validate_object(q, dst_mem, dst_origin, dst_pitch, region);
+ validate_object(q, src_mem, src_origin, src_pitch, region);
+ validate_copy(q, dst_mem, dst_origin, dst_pitch,
+ src_mem, src_origin, src_pitch, region);
hard_event *hev = new hard_event(
q, CL_COMMAND_COPY_BUFFER, deps,
- hard_copy_op(q, &dst_mem, {{ dst_offset }},
- &src_mem, {{ src_offset }},
- {{ size, 1, 1 }}));
+ hard_copy_op(q, &dst_mem, dst_origin,
+ &src_mem, src_origin, region));
ret_object(rd_ev, hev);
return CL_SUCCESS;
CLOVER_API cl_int
clEnqueueCopyBufferRect(cl_command_queue d_q, cl_mem d_src_mem,
cl_mem d_dst_mem,
- const size_t *src_origin, const size_t *dst_origin,
- const size_t *region,
+ const size_t *p_src_origin, const size_t *p_dst_origin,
+ const size_t *p_region,
size_t src_row_pitch, size_t src_slice_pitch,
size_t dst_row_pitch, size_t dst_slice_pitch,
cl_uint num_deps, const cl_event *d_deps,
cl_event *rd_ev) try {
auto &q = obj(d_q);
- auto &src_mem = obj(d_src_mem);
- auto &dst_mem = obj(d_dst_mem);
+ auto &src_mem = obj<buffer>(d_src_mem);
+ auto &dst_mem = obj<buffer>(d_dst_mem);
auto deps = objs<wait_list_tag>(d_deps, num_deps);
-
- validate_common(q, { src_mem, dst_mem }, deps);
+ auto region = vector(p_region);
+ auto dst_origin = vector(p_dst_origin);
+ auto dst_pitch = pitch(region, {{ 1, dst_row_pitch, dst_slice_pitch }});
+ auto src_origin = vector(p_src_origin);
+ auto src_pitch = pitch(region, {{ 1, src_row_pitch, src_slice_pitch }});
+
+ validate_common(q, deps);
+ validate_object(q, dst_mem, dst_origin, dst_pitch, region);
+ validate_object(q, src_mem, src_origin, src_pitch, region);
+ validate_copy(q, dst_mem, dst_origin, dst_pitch,
+ src_mem, src_origin, src_pitch, region);
hard_event *hev = new hard_event(
q, CL_COMMAND_COPY_BUFFER_RECT, deps,
- soft_copy_op(q,
- &dst_mem, vector(dst_origin),
- {{ 1, dst_row_pitch, dst_slice_pitch }},
- &src_mem, vector(src_origin),
- {{ 1, src_row_pitch, src_slice_pitch }},
- vector(region)));
+ soft_copy_op(q, &dst_mem, dst_origin, dst_pitch,
+ &src_mem, src_origin, src_pitch,
+ region));
ret_object(rd_ev, hev);
return CL_SUCCESS;
CLOVER_API cl_int
clEnqueueReadImage(cl_command_queue d_q, cl_mem d_mem, cl_bool blocking,
- const size_t *origin, const size_t *region,
+ const size_t *p_origin, const size_t *p_region,
size_t row_pitch, size_t slice_pitch, void *ptr,
cl_uint num_deps, const cl_event *d_deps,
cl_event *rd_ev) try {
auto &q = obj(d_q);
auto &img = obj<image>(d_mem);
auto deps = objs<wait_list_tag>(d_deps, num_deps);
+ auto region = vector(p_region);
+ auto dst_pitch = pitch(region, {{ img.pixel_size(),
+ row_pitch, slice_pitch }});
+ auto src_origin = vector(p_origin);
+ auto src_pitch = pitch(region, {{ img.pixel_size(),
+ img.row_pitch(), img.slice_pitch() }});
- validate_common(q, { img }, deps);
-
- if (!ptr)
- throw error(CL_INVALID_VALUE);
+ validate_common(q, deps);
+ validate_object(q, ptr, {}, dst_pitch, region);
+ validate_object(q, img, src_origin, region);
hard_event *hev = new hard_event(
q, CL_COMMAND_READ_IMAGE, deps,
- soft_copy_op(q,
- ptr, {},
- {{ 1, row_pitch, slice_pitch }},
- &img, vector(origin),
- {{ 1, img.row_pitch(), img.slice_pitch() }},
- vector(region)));
+ soft_copy_op(q, ptr, {}, dst_pitch,
+ &img, src_origin, src_pitch,
+ region));
ret_object(rd_ev, hev);
return CL_SUCCESS;
CLOVER_API cl_int
clEnqueueWriteImage(cl_command_queue d_q, cl_mem d_mem, cl_bool blocking,
- const size_t *origin, const size_t *region,
+ const size_t *p_origin, const size_t *p_region,
size_t row_pitch, size_t slice_pitch, const void *ptr,
cl_uint num_deps, const cl_event *d_deps,
cl_event *rd_ev) try {
auto &q = obj(d_q);
auto &img = obj<image>(d_mem);
auto deps = objs<wait_list_tag>(d_deps, num_deps);
+ auto region = vector(p_region);
+ auto dst_origin = vector(p_origin);
+ auto dst_pitch = pitch(region, {{ img.pixel_size(),
+ img.row_pitch(), img.slice_pitch() }});
+ auto src_pitch = pitch(region, {{ img.pixel_size(),
+ row_pitch, slice_pitch }});
- validate_common(q, { img }, deps);
-
- if (!ptr)
- throw error(CL_INVALID_VALUE);
+ validate_common(q, deps);
+ validate_object(q, img, dst_origin, region);
+ validate_object(q, ptr, {}, src_pitch, region);
hard_event *hev = new hard_event(
q, CL_COMMAND_WRITE_IMAGE, deps,
- soft_copy_op(q,
- &img, vector(origin),
- {{ 1, img.row_pitch(), img.slice_pitch() }},
- ptr, {},
- {{ 1, row_pitch, slice_pitch }},
- vector(region)));
+ soft_copy_op(q, &img, dst_origin, dst_pitch,
+ ptr, {}, src_pitch,
+ region));
ret_object(rd_ev, hev);
return CL_SUCCESS;
CLOVER_API cl_int
clEnqueueCopyImage(cl_command_queue d_q, cl_mem d_src_mem, cl_mem d_dst_mem,
- const size_t *src_origin, const size_t *dst_origin,
- const size_t *region,
+ const size_t *p_src_origin, const size_t *p_dst_origin,
+ const size_t *p_region,
cl_uint num_deps, const cl_event *d_deps,
cl_event *rd_ev) try {
auto &q = obj(d_q);
auto &src_img = obj<image>(d_src_mem);
auto &dst_img = obj<image>(d_dst_mem);
auto deps = objs<wait_list_tag>(d_deps, num_deps);
+ auto region = vector(p_region);
+ auto dst_origin = vector(p_dst_origin);
+ auto src_origin = vector(p_src_origin);
- validate_common(q, { src_img, dst_img }, deps);
+ validate_common(q, deps);
+ validate_object(q, dst_img, dst_origin, region);
+ validate_object(q, src_img, src_origin, region);
+ validate_copy(q, dst_img, dst_origin, src_img, src_origin, region);
hard_event *hev = new hard_event(
q, CL_COMMAND_COPY_IMAGE, deps,
- hard_copy_op(q,
- &dst_img, vector(dst_origin),
- &src_img, vector(src_origin),
- vector(region)));
+ hard_copy_op(q, &dst_img, dst_origin,
+ &src_img, src_origin,
+ region));
ret_object(rd_ev, hev);
return CL_SUCCESS;
CLOVER_API cl_int
clEnqueueCopyImageToBuffer(cl_command_queue d_q,
cl_mem d_src_mem, cl_mem d_dst_mem,
- const size_t *src_origin, const size_t *region,
+ const size_t *p_src_origin, const size_t *p_region,
size_t dst_offset,
cl_uint num_deps, const cl_event *d_deps,
cl_event *rd_ev) try {
auto &q = obj(d_q);
auto &src_img = obj<image>(d_src_mem);
- auto &dst_mem = obj(d_dst_mem);
+ auto &dst_mem = obj<buffer>(d_dst_mem);
auto deps = objs<wait_list_tag>(d_deps, num_deps);
-
- validate_common(q, { src_img, dst_mem }, deps);
+ auto region = vector(p_region);
+ vector_t dst_origin = { dst_offset };
+ auto dst_pitch = pitch(region, {{ src_img.pixel_size() }});
+ auto src_origin = vector(p_src_origin);
+ auto src_pitch = pitch(region, {{ src_img.pixel_size(),
+ src_img.row_pitch(),
+ src_img.slice_pitch() }});
+
+ validate_common(q, deps);
+ validate_object(q, dst_mem, dst_origin, dst_pitch, region);
+ validate_object(q, src_img, src_origin, region);
hard_event *hev = new hard_event(
q, CL_COMMAND_COPY_IMAGE_TO_BUFFER, deps,
- soft_copy_op(q,
- &dst_mem, {{ dst_offset }},
- {{ 0, 0, 0 }},
- &src_img, vector(src_origin),
- {{ 1, src_img.row_pitch(), src_img.slice_pitch() }},
- vector(region)));
+ soft_copy_op(q, &dst_mem, dst_origin, dst_pitch,
+ &src_img, src_origin, src_pitch,
+ region));
ret_object(rd_ev, hev);
return CL_SUCCESS;
clEnqueueCopyBufferToImage(cl_command_queue d_q,
cl_mem d_src_mem, cl_mem d_dst_mem,
size_t src_offset,
- const size_t *dst_origin, const size_t *region,
+ const size_t *p_dst_origin, const size_t *p_region,
cl_uint num_deps, const cl_event *d_deps,
cl_event *rd_ev) try {
auto &q = obj(d_q);
- auto &src_mem = obj(d_src_mem);
+ auto &src_mem = obj<buffer>(d_src_mem);
auto &dst_img = obj<image>(d_dst_mem);
auto deps = objs<wait_list_tag>(d_deps, num_deps);
-
- validate_common(q, { src_mem, dst_img }, deps);
+ auto region = vector(p_region);
+ auto dst_origin = vector(p_dst_origin);
+ auto dst_pitch = pitch(region, {{ dst_img.pixel_size(),
+ dst_img.row_pitch(),
+ dst_img.slice_pitch() }});
+ vector_t src_origin = { src_offset };
+ auto src_pitch = pitch(region, {{ dst_img.pixel_size() }});
+
+ validate_common(q, deps);
+ validate_object(q, dst_img, dst_origin, region);
+ validate_object(q, src_mem, src_origin, src_pitch, region);
hard_event *hev = new hard_event(
q, CL_COMMAND_COPY_BUFFER_TO_IMAGE, deps,
- soft_copy_op(q,
- &dst_img, vector(dst_origin),
- {{ 1, dst_img.row_pitch(), dst_img.slice_pitch() }},
- &src_mem, {{ src_offset }},
- {{ 0, 0, 0 }},
- vector(region)));
+ soft_copy_op(q, &dst_img, dst_origin, dst_pitch,
+ &src_mem, src_origin, src_pitch,
+ region));
ret_object(rd_ev, hev);
return CL_SUCCESS;
cl_uint num_deps, const cl_event *d_deps,
cl_event *rd_ev, cl_int *r_errcode) try {
auto &q = obj(d_q);
- auto &mem = obj(d_mem);
+ auto &mem = obj<buffer>(d_mem);
auto deps = objs<wait_list_tag>(d_deps, num_deps);
+ vector_t region = { size, 1, 1 };
+ vector_t obj_origin = { offset };
+ auto obj_pitch = pitch(region, {{ 1 }});
- validate_common(q, { mem }, deps);
-
- if (offset > mem.size() || offset + size > mem.size())
- throw error(CL_INVALID_VALUE);
+ validate_common(q, deps);
+ validate_object(q, mem, obj_origin, obj_pitch, region);
- void *map = mem.resource(q).add_map(
- q, flags, blocking, {{ offset }}, {{ size }});
+ void *map = mem.resource(q).add_map(q, flags, blocking, obj_origin, region);
ret_object(rd_ev, new hard_event(q, CL_COMMAND_MAP_BUFFER, deps));
ret_error(r_errcode, CL_SUCCESS);
CLOVER_API void *
clEnqueueMapImage(cl_command_queue d_q, cl_mem d_mem, cl_bool blocking,
cl_map_flags flags,
- const size_t *origin, const size_t *region,
+ const size_t *p_origin, const size_t *p_region,
size_t *row_pitch, size_t *slice_pitch,
cl_uint num_deps, const cl_event *d_deps,
cl_event *rd_ev, cl_int *r_errcode) try {
auto &q = obj(d_q);
auto &img = obj<image>(d_mem);
auto deps = objs<wait_list_tag>(d_deps, num_deps);
+ auto region = vector(p_region);
+ auto origin = vector(p_origin);
- validate_common(q, { img }, deps);
+ validate_common(q, deps);
+ validate_object(q, img, origin, region);
- void *map = img.resource(q).add_map(
- q, flags, blocking, vector(origin), vector(region));
+ void *map = img.resource(q).add_map(q, flags, blocking, origin, region);
ret_object(rd_ev, new hard_event(q, CL_COMMAND_MAP_IMAGE, deps));
ret_error(r_errcode, CL_SUCCESS);
auto &mem = obj(d_mem);
auto deps = objs<wait_list_tag>(d_deps, num_deps);
- validate_common(q, { mem }, deps);
+ validate_common(q, deps);
hard_event *hev = new hard_event(
q, CL_COMMAND_UNMAP_MEM_OBJECT, deps,