/*
* Copyright © 2012 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see .
*
*/
#include "cl_mem.h"
#include "cl_enqueue.h"
#include "cl_command_queue.h"
#include "cl_event.h"
#include "CL/cl.h"
#include
cl_int
clSetMemObjectDestructorCallback(cl_mem memobj,
void(CL_CALLBACK *pfn_notify)(cl_mem, void *),
void *user_data)
{
if (!CL_OBJECT_IS_MEM(memobj))
return CL_INVALID_MEM_OBJECT;
if (pfn_notify == NULL)
return CL_INVALID_VALUE;
return cl_mem_set_destructor_callback(memobj, pfn_notify, user_data);
}
cl_int
clGetMemObjectInfo(cl_mem memobj,
cl_mem_info param_name,
size_t param_value_size,
void *param_value,
size_t *param_value_size_ret)
{
const void *src_ptr = NULL;
size_t src_size = 0;
cl_mem_object_type type;
size_t ptr, offset;
cl_int ref;
cl_mem parent;
if (!CL_OBJECT_IS_MEM(memobj)) {
return CL_INVALID_MEM_OBJECT;
}
switch (param_name) {
case CL_MEM_TYPE: {
type = cl_get_mem_object_type(memobj);
src_ptr = &type;
src_size = sizeof(cl_mem_object_type);
break;
}
case CL_MEM_FLAGS:
src_ptr = &memobj->flags;
src_size = sizeof(cl_mem_flags);
break;
case CL_MEM_SIZE:
src_ptr = &memobj->size;
src_size = sizeof(size_t);
break;
case CL_MEM_HOST_PTR: {
ptr = 0;
if (memobj->type == CL_MEM_IMAGE_TYPE) {
ptr = (size_t)memobj->host_ptr;
} else {
struct _cl_mem_buffer *buf = (struct _cl_mem_buffer *)memobj;
ptr = (size_t)memobj->host_ptr + buf->sub_offset;
}
src_ptr = &ptr;
src_size = sizeof(size_t);
break;
}
case CL_MEM_USES_SVM_POINTER: {
src_ptr = &memobj->is_svm;
src_size = sizeof(memobj->is_svm);
break;
}
case CL_MEM_MAP_COUNT:
src_ptr = &memobj->map_ref;
src_size = sizeof(cl_uint);
break;
case CL_MEM_REFERENCE_COUNT: {
ref = CL_OBJECT_GET_REF(memobj);
src_ptr = &ref;
src_size = sizeof(cl_int);
break;
}
case CL_MEM_CONTEXT:
src_ptr = &memobj->ctx;
src_size = sizeof(cl_context);
break;
case CL_MEM_ASSOCIATED_MEMOBJECT: {
parent = NULL;
if (memobj->type == CL_MEM_SUBBUFFER_TYPE) {
struct _cl_mem_buffer *buf = (struct _cl_mem_buffer *)memobj;
parent = (cl_mem)(buf->parent);
} else if (memobj->type == CL_MEM_IMAGE_TYPE) {
parent = memobj;
} else if (memobj->type == CL_MEM_BUFFER1D_IMAGE_TYPE) {
struct _cl_mem_buffer1d_image *image_buffer = (struct _cl_mem_buffer1d_image *)memobj;
parent = image_buffer->descbuffer;
} else
parent = NULL;
src_ptr = &parent;
src_size = sizeof(cl_mem);
break;
}
case CL_MEM_OFFSET: {
offset = 0;
if (memobj->type == CL_MEM_SUBBUFFER_TYPE) {
struct _cl_mem_buffer *buf = (struct _cl_mem_buffer *)memobj;
offset = buf->sub_offset;
}
src_ptr = &offset;
src_size = sizeof(size_t);
break;
}
default:
return CL_INVALID_VALUE;
}
return cl_get_info_helper(src_ptr, src_size,
param_value, param_value_size, param_value_size_ret);
}
cl_int
clGetImageInfo(cl_mem memobj,
cl_image_info param_name,
size_t param_value_size,
void *param_value,
size_t *param_value_size_ret)
{
const void *src_ptr = NULL;
size_t src_size = 0;
struct _cl_mem_image *image;
size_t height, depth, array_sz;
cl_uint value;
if (!CL_OBJECT_IS_MEM(memobj)) {
return CL_INVALID_MEM_OBJECT;
}
image = cl_mem_image(memobj);
switch (param_name) {
case CL_IMAGE_FORMAT:
src_ptr = &image->fmt;
src_size = sizeof(cl_image_format);
break;
case CL_IMAGE_ELEMENT_SIZE:
src_ptr = &image->bpp;
src_size = sizeof(size_t);
break;
case CL_IMAGE_ROW_PITCH:
src_ptr = &image->row_pitch;
src_size = sizeof(size_t);
break;
case CL_IMAGE_SLICE_PITCH:
src_ptr = &image->slice_pitch;
src_size = sizeof(size_t);
break;
case CL_IMAGE_WIDTH:
if (memobj->type == CL_MEM_BUFFER1D_IMAGE_TYPE) {
struct _cl_mem_buffer1d_image *buffer1d_image = (struct _cl_mem_buffer1d_image *)image;
src_ptr = &buffer1d_image->size;
} else {
src_ptr = &image->w;
}
src_size = sizeof(size_t);
break;
case CL_IMAGE_HEIGHT: {
height = 0;
if (memobj->type != CL_MEM_BUFFER1D_IMAGE_TYPE) {
height = IS_1D_IMAGE(image) ? 0 : image->h;
}
src_ptr = &height;
src_size = sizeof(size_t);
break;
}
case CL_IMAGE_DEPTH: {
depth = 0;
depth = IS_3D_IMAGE(image) ? image->depth : 0;
src_ptr = &depth;
src_size = sizeof(size_t);
break;
}
case CL_IMAGE_ARRAY_SIZE: {
array_sz = 0;
array_sz = IS_IMAGE_ARRAY(image) ? image->depth : 0;
src_ptr = &array_sz;
src_size = sizeof(size_t);
break;
}
case CL_IMAGE_BUFFER:
src_ptr = &image->buffer_1d;
src_size = sizeof(cl_mem);
break;
case CL_IMAGE_NUM_MIP_LEVELS:
case CL_IMAGE_NUM_SAMPLES: {
value = 0;
src_ptr = &value;
src_size = sizeof(cl_uint);
break;
}
default:
return CL_INVALID_VALUE;
}
return cl_get_info_helper(src_ptr, src_size,
param_value, param_value_size, param_value_size_ret);
}
void *
clEnqueueMapBuffer(cl_command_queue command_queue,
cl_mem buffer,
cl_bool blocking_map,
cl_map_flags map_flags,
size_t offset,
size_t size,
cl_uint num_events_in_wait_list,
const cl_event *event_wait_list,
cl_event *event,
cl_int *errcode_ret)
{
cl_int err = CL_SUCCESS;
void *ptr = NULL;
void *mem_ptr = NULL;
cl_event e = NULL;
cl_int e_status;
enqueue_data *data = NULL;
do {
if (!CL_OBJECT_IS_COMMAND_QUEUE(command_queue)) {
err = CL_INVALID_COMMAND_QUEUE;
break;
}
if (!CL_OBJECT_IS_BUFFER(buffer)) {
err = CL_INVALID_MEM_OBJECT;
break;
}
if (command_queue->ctx != buffer->ctx) {
err = CL_INVALID_CONTEXT;
break;
}
if (!size || offset + size > buffer->size) {
err = CL_INVALID_VALUE;
break;
}
if ((map_flags & CL_MAP_READ &&
buffer->flags & (CL_MEM_HOST_WRITE_ONLY | CL_MEM_HOST_NO_ACCESS)) ||
(map_flags & (CL_MAP_WRITE | CL_MAP_WRITE_INVALIDATE_REGION) &&
buffer->flags & (CL_MEM_HOST_READ_ONLY | CL_MEM_HOST_NO_ACCESS))) {
err = CL_INVALID_OPERATION;
break;
}
err = cl_event_check_waitlist(num_events_in_wait_list, event_wait_list,
event, command_queue->ctx);
if (err != CL_SUCCESS) {
break;
}
e = cl_event_create(command_queue->ctx, command_queue, num_events_in_wait_list,
event_wait_list, CL_COMMAND_MAP_BUFFER, &err);
if (err != CL_SUCCESS) {
break;
}
if (blocking_map) {
err = cl_event_wait_for_event_ready(e);
if (err != CL_SUCCESS)
break;
/* Blocking call API is a sync point of flush. */
err = cl_command_queue_wait_flush(command_queue);
if (err != CL_SUCCESS) {
break;
}
}
e_status = cl_event_is_ready(e);
if (e_status < CL_COMPLETE) {
err = CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST;
break;
}
data = &e->exec_data;
data->type = EnqueueMapBuffer;
data->mem_obj = buffer;
data->offset = offset;
data->size = size;
data->ptr = NULL;
data->unsync_map = 0;
if (map_flags & (CL_MAP_WRITE | CL_MAP_WRITE_INVALIDATE_REGION))
data->write_map = 1;
if (cl_command_queue_allow_bypass_submit(command_queue) && (e_status == CL_COMPLETE)) {
// Sync mode, no need to queue event.
err = cl_event_exec(e, CL_COMPLETE, CL_FALSE);
if (err != CL_SUCCESS) {
break;
}
} else {
err = cl_event_exec(e, CL_SUBMITTED, CL_TRUE); // Submit to get the address.
if (err != CL_SUCCESS) {
break;
}
cl_command_queue_enqueue_event(command_queue, e);
if (blocking_map) {
cl_event_wait_for_events_list(1, &e);
}
}
ptr = data->ptr;
assert(ptr);
err = cl_mem_record_map_mem(buffer, ptr, &mem_ptr, offset, size, NULL, NULL);
assert(err == CL_SUCCESS);
} while (0);
if (err == CL_SUCCESS && event) {
*event = e;
} else {
cl_event_delete(e);
}
if (errcode_ret)
*errcode_ret = err;
return mem_ptr;
}
static cl_int
clEnqueueUnmapMemObjectForKernel(cl_command_queue command_queue,
cl_mem memobj,
void *mapped_ptr,
cl_uint num_events_in_wait_list,
const cl_event *event_wait_list,
cl_event *event)
{
cl_int err = CL_SUCCESS;
int i, j;
uint8_t write_map = 0;
cl_mem tmp_ker_buf = NULL;
size_t origin[3], region[3];
void *v_ptr = NULL;
assert(memobj->mapped_ptr_sz >= memobj->map_ref);
for (i = 0; i < memobj->mapped_ptr_sz; i++) {
if (memobj->mapped_ptr[i].ptr == mapped_ptr) {
memobj->mapped_ptr[i].ptr = NULL;
v_ptr = memobj->mapped_ptr[i].v_ptr;
write_map = memobj->mapped_ptr[i].ker_write_map;
tmp_ker_buf = memobj->mapped_ptr[i].tmp_ker_buf;
for (j = 0; j < 3; j++) {
region[j] = memobj->mapped_ptr[i].region[j];
origin[j] = memobj->mapped_ptr[i].origin[j];
memobj->mapped_ptr[i].region[j] = 0;
memobj->mapped_ptr[i].origin[j] = 0;
}
memobj->mapped_ptr[i].size = 0;
memobj->mapped_ptr[i].ker_write_map = 0;
memobj->mapped_ptr[i].tmp_ker_buf = 0;
memobj->mapped_ptr[i].v_ptr = NULL;
memobj->map_ref--;
break;
}
}
if (!tmp_ker_buf)
return CL_INVALID_MEM_OBJECT;
cl_event e;
err = clEnqueueUnmapMemObject(command_queue, tmp_ker_buf, v_ptr,
num_events_in_wait_list, event_wait_list, &e);
if (err != CL_SUCCESS) {
clReleaseEvent(e);
return err;
}
if (write_map) {
err = clEnqueueCopyBufferToImage(command_queue, tmp_ker_buf, memobj, 0, origin, region,
1, &e, event);
if (err != CL_SUCCESS) {
clReleaseEvent(e);
return err;
}
if (event == NULL) {
err = clFinish(command_queue);
if (err != CL_SUCCESS) {
clReleaseEvent(e);
return err;
}
}
}
clReleaseEvent(e);
clReleaseMemObject(tmp_ker_buf);
return err;
}
cl_int
clEnqueueUnmapMemObject(cl_command_queue command_queue,
cl_mem memobj,
void *mapped_ptr,
cl_uint num_events_in_wait_list,
const cl_event *event_wait_list,
cl_event *event)
{
cl_int err = CL_SUCCESS;
cl_int e_status;
enqueue_data *data = NULL;
cl_event e = NULL;
do {
if (!CL_OBJECT_IS_COMMAND_QUEUE(command_queue)) {
err = CL_INVALID_COMMAND_QUEUE;
break;
}
if (!CL_OBJECT_IS_MEM(memobj)) {
err = CL_INVALID_MEM_OBJECT;
break;
}
if (command_queue->ctx != memobj->ctx) {
err = CL_INVALID_CONTEXT;
break;
}
if (CL_OBJECT_IS_IMAGE(memobj) && cl_mem_image(memobj)->is_ker_copy) {
return clEnqueueUnmapMemObjectForKernel(command_queue, memobj, mapped_ptr,
num_events_in_wait_list, event_wait_list, event);
}
err = cl_event_check_waitlist(num_events_in_wait_list, event_wait_list,
event, command_queue->ctx);
if (err != CL_SUCCESS) {
break;
}
e = cl_event_create(command_queue->ctx, command_queue, num_events_in_wait_list,
event_wait_list, CL_COMMAND_UNMAP_MEM_OBJECT, &err);
if (err != CL_SUCCESS) {
break;
}
e_status = cl_event_is_ready(e);
if (e_status < CL_COMPLETE) {
err = CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST;
break;
}
data = &e->exec_data;
data->type = EnqueueUnmapMemObject;
data->mem_obj = memobj;
data->ptr = mapped_ptr;
if (cl_command_queue_allow_bypass_submit(command_queue) && (e_status == CL_COMPLETE)) { // No need to wait
err = cl_event_exec(e, CL_COMPLETE, CL_FALSE);
if (err != CL_SUCCESS) {
break;
}
} else { // May need to wait some event to complete.
err = cl_event_exec(e, CL_QUEUED, CL_FALSE);
if (err != CL_SUCCESS) {
break;
}
cl_command_queue_enqueue_event(command_queue, e);
}
} while (0);
if (err == CL_SUCCESS && event) {
*event = e;
} else {
cl_event_delete(e);
}
return err;
}
cl_int
clEnqueueReadBuffer(cl_command_queue command_queue,
cl_mem buffer,
cl_bool blocking_read,
size_t offset,
size_t size,
void *ptr,
cl_uint num_events_in_wait_list,
const cl_event *event_wait_list,
cl_event *event)
{
cl_int err = CL_SUCCESS;
enqueue_data *data = NULL;
cl_int e_status;
cl_event e = NULL;
do {
if (!CL_OBJECT_IS_COMMAND_QUEUE(command_queue)) {
err = CL_INVALID_COMMAND_QUEUE;
break;
}
if (!CL_OBJECT_IS_BUFFER(buffer)) {
err = CL_INVALID_MEM_OBJECT;
break;
}
if (command_queue->ctx != buffer->ctx) {
err = CL_INVALID_CONTEXT;
break;
}
if (!ptr || !size || offset + size > buffer->size) {
err = CL_INVALID_VALUE;
break;
}
if (buffer->flags & (CL_MEM_HOST_WRITE_ONLY | CL_MEM_HOST_NO_ACCESS)) {
err = CL_INVALID_OPERATION;
break;
}
err = cl_event_check_waitlist(num_events_in_wait_list, event_wait_list,
event, command_queue->ctx);
if (err != CL_SUCCESS) {
break;
}
e = cl_event_create(command_queue->ctx, command_queue, num_events_in_wait_list,
event_wait_list, CL_COMMAND_READ_BUFFER, &err);
if (err != CL_SUCCESS) {
break;
}
if (blocking_read) {
err = cl_event_wait_for_event_ready(e);
if (err != CL_SUCCESS)
break;
/* Blocking call API is a sync point of flush. */
err = cl_command_queue_wait_flush(command_queue);
if (err != CL_SUCCESS) {
break;
}
}
e_status = cl_event_is_ready(e);
if (e_status < CL_COMPLETE) {
err = CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST;
break;
}
data = &e->exec_data;
data->type = EnqueueReadBuffer;
data->mem_obj = buffer;
data->ptr = ptr;
data->offset = offset;
data->size = size;
if (cl_command_queue_allow_bypass_submit(command_queue) && (e_status == CL_COMPLETE)) {
// Sync mode, no need to queue event.
err = cl_event_exec(e, CL_COMPLETE, CL_FALSE);
if (err != CL_SUCCESS) {
break;
}
} else {
err = cl_event_exec(e, CL_QUEUED, CL_FALSE);
if (err != CL_SUCCESS) {
break;
}
cl_command_queue_enqueue_event(command_queue, e);
if (blocking_read) {
cl_event_wait_for_events_list(1, &e);
}
}
} while (0);
if (err == CL_SUCCESS && event) {
*event = e;
} else {
cl_event_delete(e);
}
return err;
}
cl_int
clEnqueueWriteBuffer(cl_command_queue command_queue,
cl_mem buffer,
cl_bool blocking_write,
size_t offset,
size_t size,
const void *ptr,
cl_uint num_events_in_wait_list,
const cl_event *event_wait_list,
cl_event *event)
{
cl_int err = CL_SUCCESS;
enqueue_data *data = NULL;
cl_int e_status;
cl_event e = NULL;
do {
if (!CL_OBJECT_IS_COMMAND_QUEUE(command_queue)) {
err = CL_INVALID_COMMAND_QUEUE;
break;
}
if (!CL_OBJECT_IS_BUFFER(buffer)) {
err = CL_INVALID_MEM_OBJECT;
break;
}
if (command_queue->ctx != buffer->ctx) {
err = CL_INVALID_CONTEXT;
break;
}
if (!ptr || !size || offset + size > buffer->size) {
err = CL_INVALID_VALUE;
break;
}
if (buffer->flags & (CL_MEM_HOST_READ_ONLY | CL_MEM_HOST_NO_ACCESS)) {
err = CL_INVALID_OPERATION;
break;
}
err = cl_event_check_waitlist(num_events_in_wait_list, event_wait_list,
event, command_queue->ctx);
if (err != CL_SUCCESS) {
break;
}
e = cl_event_create(command_queue->ctx, command_queue, num_events_in_wait_list,
event_wait_list, CL_COMMAND_WRITE_BUFFER, &err);
if (err != CL_SUCCESS) {
break;
}
if (blocking_write) {
err = cl_event_wait_for_event_ready(e);
if (err != CL_SUCCESS)
break;
/* Blocking call API is a sync point of flush. */
err = cl_command_queue_wait_flush(command_queue);
if (err != CL_SUCCESS) {
break;
}
}
e_status = cl_event_is_ready(e);
if (e_status < CL_COMPLETE) {
err = CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST;
break;
}
data = &e->exec_data;
data->type = EnqueueWriteBuffer;
data->mem_obj = buffer;
data->const_ptr = ptr;
data->offset = offset;
data->size = size;
if (cl_command_queue_allow_bypass_submit(command_queue) && (e_status == CL_COMPLETE)) {
// Sync mode, no need to queue event.
err = cl_event_exec(e, CL_COMPLETE, CL_FALSE);
if (err != CL_SUCCESS) {
break;
}
} else {
err = cl_event_exec(e, CL_QUEUED, CL_FALSE);
if (err != CL_SUCCESS) {
break;
}
cl_command_queue_enqueue_event(command_queue, e);
if (blocking_write) {
cl_event_wait_for_events_list(1, &e);
}
}
} while (0);
if (err == CL_SUCCESS && event) {
*event = e;
} else {
cl_event_delete(e);
}
return err;
}
cl_int
clEnqueueReadBufferRect(cl_command_queue command_queue,
cl_mem buffer,
cl_bool blocking_read,
const size_t *buffer_origin,
const size_t *host_origin,
const size_t *region,
size_t buffer_row_pitch,
size_t buffer_slice_pitch,
size_t host_row_pitch,
size_t host_slice_pitch,
void *ptr,
cl_uint num_events_in_wait_list,
const cl_event *event_wait_list,
cl_event *event)
{
cl_int err = CL_SUCCESS;
size_t total_size = 0;
enqueue_data *data = NULL;
cl_int e_status;
cl_event e = NULL;
do {
if (!CL_OBJECT_IS_COMMAND_QUEUE(command_queue)) {
err = CL_INVALID_COMMAND_QUEUE;
break;
}
if (!CL_OBJECT_IS_BUFFER(buffer)) {
err = CL_INVALID_MEM_OBJECT;
break;
}
if (command_queue->ctx != buffer->ctx) {
err = CL_INVALID_CONTEXT;
break;
}
if (buffer->flags & (CL_MEM_HOST_WRITE_ONLY | CL_MEM_HOST_NO_ACCESS)) {
err = CL_INVALID_OPERATION;
break;
}
if (!ptr || !region || region[0] == 0 || region[1] == 0 || region[2] == 0) {
err = CL_INVALID_VALUE;
break;
}
if (buffer_row_pitch == 0)
buffer_row_pitch = region[0];
if (buffer_slice_pitch == 0)
buffer_slice_pitch = region[1] * buffer_row_pitch;
if (host_row_pitch == 0)
host_row_pitch = region[0];
if (host_slice_pitch == 0)
host_slice_pitch = region[1] * host_row_pitch;
if (buffer_row_pitch < region[0] ||
host_row_pitch < region[0]) {
err = CL_INVALID_VALUE;
break;
}
if ((buffer_slice_pitch < region[1] * buffer_row_pitch || buffer_slice_pitch % buffer_row_pitch != 0) ||
(host_slice_pitch < region[1] * host_row_pitch || host_slice_pitch % host_row_pitch != 0)) {
err = CL_INVALID_VALUE;
break;
}
total_size = (buffer_origin[2] + region[2] - 1) * buffer_slice_pitch +
(buffer_origin[1] + region[1] - 1) * buffer_row_pitch + buffer_origin[0] + region[0];
if (total_size > buffer->size) {
err = CL_INVALID_VALUE;
break;
}
err = cl_event_check_waitlist(num_events_in_wait_list, event_wait_list,
event, command_queue->ctx);
if (err != CL_SUCCESS) {
break;
}
e = cl_event_create(command_queue->ctx, command_queue, num_events_in_wait_list,
event_wait_list, CL_COMMAND_READ_BUFFER_RECT, &err);
if (err != CL_SUCCESS) {
break;
}
if (blocking_read) {
err = cl_event_wait_for_event_ready(e);
if (err != CL_SUCCESS)
break;
/* Blocking call API is a sync point of flush. */
err = cl_command_queue_wait_flush(command_queue);
if (err != CL_SUCCESS) {
break;
}
}
e_status = cl_event_is_ready(e);
if (e_status < CL_COMPLETE) {
err = CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST;
break;
}
data = &e->exec_data;
data->type = EnqueueReadBufferRect;
data->mem_obj = buffer;
data->ptr = ptr;
data->origin[0] = buffer_origin[0];
data->origin[1] = buffer_origin[1];
data->origin[2] = buffer_origin[2];
data->host_origin[0] = host_origin[0];
data->host_origin[1] = host_origin[1];
data->host_origin[2] = host_origin[2];
data->region[0] = region[0];
data->region[1] = region[1];
data->region[2] = region[2];
data->row_pitch = buffer_row_pitch;
data->slice_pitch = buffer_slice_pitch;
data->host_row_pitch = host_row_pitch;
data->host_slice_pitch = host_slice_pitch;
if (cl_command_queue_allow_bypass_submit(command_queue) && (e_status == CL_COMPLETE)) {
// Sync mode, no need to queue event.
err = cl_event_exec(e, CL_COMPLETE, CL_FALSE);
if (err != CL_SUCCESS) {
break;
}
} else {
err = cl_event_exec(e, CL_QUEUED, CL_FALSE);
if (err != CL_SUCCESS) {
break;
}
cl_command_queue_enqueue_event(command_queue, e);
if (blocking_read) {
cl_event_wait_for_events_list(1, &e);
}
}
} while (0);
if (err == CL_SUCCESS && event) {
*event = e;
} else {
cl_event_delete(e);
}
return err;
}
cl_int
clEnqueueWriteBufferRect(cl_command_queue command_queue,
cl_mem buffer,
cl_bool blocking_write,
const size_t *buffer_origin,
const size_t *host_origin,
const size_t *region,
size_t buffer_row_pitch,
size_t buffer_slice_pitch,
size_t host_row_pitch,
size_t host_slice_pitch,
const void *ptr,
cl_uint num_events_in_wait_list,
const cl_event *event_wait_list,
cl_event *event)
{
cl_int err = CL_SUCCESS;
size_t total_size = 0;
enqueue_data *data = NULL;
cl_int e_status;
cl_event e = NULL;
do {
if (!CL_OBJECT_IS_COMMAND_QUEUE(command_queue)) {
err = CL_INVALID_COMMAND_QUEUE;
break;
}
if (!CL_OBJECT_IS_BUFFER(buffer)) {
err = CL_INVALID_MEM_OBJECT;
break;
}
if (command_queue->ctx != buffer->ctx) {
err = CL_INVALID_CONTEXT;
break;
}
if (buffer->flags & (CL_MEM_HOST_READ_ONLY | CL_MEM_HOST_NO_ACCESS)) {
err = CL_INVALID_OPERATION;
break;
}
if (!ptr || !region || region[0] == 0 || region[1] == 0 || region[2] == 0) {
err = CL_INVALID_VALUE;
break;
}
if (buffer_row_pitch == 0)
buffer_row_pitch = region[0];
if (buffer_slice_pitch == 0)
buffer_slice_pitch = region[1] * buffer_row_pitch;
if (host_row_pitch == 0)
host_row_pitch = region[0];
if (host_slice_pitch == 0)
host_slice_pitch = region[1] * host_row_pitch;
if (buffer_row_pitch < region[0] ||
host_row_pitch < region[0]) {
err = CL_INVALID_VALUE;
break;
}
if ((buffer_slice_pitch < region[1] * buffer_row_pitch || buffer_slice_pitch % buffer_row_pitch != 0) ||
(host_slice_pitch < region[1] * host_row_pitch || host_slice_pitch % host_row_pitch != 0)) {
err = CL_INVALID_VALUE;
break;
}
total_size = (buffer_origin[2] + region[2] - 1) * buffer_slice_pitch +
(buffer_origin[1] + region[1] - 1) * buffer_row_pitch +
buffer_origin[0] + region[0];
if (total_size > buffer->size) {
err = CL_INVALID_VALUE;
break;
}
err = cl_event_check_waitlist(num_events_in_wait_list, event_wait_list,
event, command_queue->ctx);
if (err != CL_SUCCESS) {
break;
}
e = cl_event_create(command_queue->ctx, command_queue, num_events_in_wait_list,
event_wait_list, CL_COMMAND_WRITE_BUFFER_RECT, &err);
if (err != CL_SUCCESS) {
break;
}
if (blocking_write) {
err = cl_event_wait_for_event_ready(e);
if (err != CL_SUCCESS)
break;
/* Blocking call API is a sync point of flush. */
err = cl_command_queue_wait_flush(command_queue);
if (err != CL_SUCCESS) {
break;
}
}
e_status = cl_event_is_ready(e);
if (e_status < CL_COMPLETE) {
err = CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST;
break;
}
data = &e->exec_data;
data->type = EnqueueWriteBufferRect;
data->mem_obj = buffer;
data->const_ptr = ptr;
data->origin[0] = buffer_origin[0];
data->origin[1] = buffer_origin[1];
data->origin[2] = buffer_origin[2];
data->host_origin[0] = host_origin[0];
data->host_origin[1] = host_origin[1];
data->host_origin[2] = host_origin[2];
data->region[0] = region[0];
data->region[1] = region[1];
data->region[2] = region[2];
data->row_pitch = buffer_row_pitch;
data->slice_pitch = buffer_slice_pitch;
data->host_row_pitch = host_row_pitch;
data->host_slice_pitch = host_slice_pitch;
if (cl_command_queue_allow_bypass_submit(command_queue) && (e_status == CL_COMPLETE)) {
// Sync mode, no need to queue event.
err = cl_event_exec(e, CL_COMPLETE, CL_FALSE);
if (err != CL_SUCCESS) {
break;
}
} else {
err = cl_event_exec(e, CL_QUEUED, CL_FALSE);
if (err != CL_SUCCESS) {
break;
}
cl_command_queue_enqueue_event(command_queue, e);
if (blocking_write) {
cl_event_wait_for_events_list(1, &e);
}
}
} while (0);
if (err == CL_SUCCESS && event) {
*event = e;
} else {
cl_event_delete(e);
}
return err;
}
cl_int
clEnqueueCopyBuffer(cl_command_queue command_queue,
cl_mem src_buffer,
cl_mem dst_buffer,
size_t src_offset,
size_t dst_offset,
size_t cb,
cl_uint num_events_in_wait_list,
const cl_event *event_wait_list,
cl_event *event)
{
cl_int err = CL_SUCCESS;
cl_event e = NULL;
cl_int e_status;
do {
if (!CL_OBJECT_IS_COMMAND_QUEUE(command_queue)) {
err = CL_INVALID_COMMAND_QUEUE;
break;
}
if (!CL_OBJECT_IS_MEM(src_buffer)) {
err = CL_INVALID_MEM_OBJECT;
break;
}
if (!CL_OBJECT_IS_MEM(dst_buffer)) {
err = CL_INVALID_MEM_OBJECT;
break;
}
if (command_queue->ctx != src_buffer->ctx) {
err = CL_INVALID_CONTEXT;
break;
}
if (command_queue->ctx != dst_buffer->ctx) {
err = CL_INVALID_CONTEXT;
break;
}
if (src_offset + cb > src_buffer->size) {
err = CL_INVALID_VALUE;
break;
}
if (dst_offset + cb > dst_buffer->size) {
err = CL_INVALID_VALUE;
break;
}
/* Check overlap */
if (src_buffer == dst_buffer && (src_offset <= dst_offset && dst_offset <= src_offset + cb - 1) &&
(dst_offset <= src_offset && src_offset <= dst_offset + cb - 1)) {
err = CL_MEM_COPY_OVERLAP;
break;
}
/* Check sub overlap */
if (src_buffer->type == CL_MEM_SUBBUFFER_TYPE && dst_buffer->type == CL_MEM_SUBBUFFER_TYPE) {
struct _cl_mem_buffer *src_b = (struct _cl_mem_buffer *)src_buffer;
struct _cl_mem_buffer *dst_b = (struct _cl_mem_buffer *)dst_buffer;
size_t src_sub_offset = src_b->sub_offset;
size_t dst_sub_offset = dst_b->sub_offset;
if ((src_offset + src_sub_offset <= dst_offset + dst_sub_offset &&
dst_offset + dst_sub_offset <= src_offset + src_sub_offset + cb - 1) &&
(dst_offset + dst_sub_offset <= src_offset + src_sub_offset &&
src_offset + src_sub_offset <= dst_offset + dst_sub_offset + cb - 1)) {
err = CL_MEM_COPY_OVERLAP;
break;
}
}
err = cl_event_check_waitlist(num_events_in_wait_list, event_wait_list,
event, command_queue->ctx);
if (err != CL_SUCCESS) {
break;
}
e = cl_event_create(command_queue->ctx, command_queue, num_events_in_wait_list,
event_wait_list, CL_COMMAND_COPY_BUFFER, &err);
if (err != CL_SUCCESS) {
break;
}
err = cl_mem_copy(command_queue, e, src_buffer, dst_buffer, src_offset, dst_offset, cb);
if (err != CL_SUCCESS) {
break;
}
/* We will flush the ndrange if no event depend. Else we will add it to queue list.
The finish or Complete status will always be done in queue list. */
e_status = cl_event_is_ready(e);
if (e_status < CL_COMPLETE) { // Error happend, cancel.
err = CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST;
break;
}
err = cl_event_exec(e, (cl_command_queue_allow_bypass_submit(command_queue) && (e_status == CL_COMPLETE)) ? CL_SUBMITTED : CL_QUEUED, CL_FALSE);
if (err != CL_SUCCESS) {
break;
}
cl_command_queue_enqueue_event(command_queue, e);
} while (0);
if (err == CL_SUCCESS && event) {
*event = e;
} else {
cl_event_delete(e);
}
return err;
}
/* The following code checking overlap is from Appendix of openCL spec 1.1 */
static cl_bool
check_copy_overlap(const size_t src_offset[3],
const size_t dst_offset[3],
const size_t region[3],
size_t row_pitch, size_t slice_pitch)
{
const size_t src_min[] = {src_offset[0], src_offset[1], src_offset[2]};
const size_t src_max[] = {src_offset[0] + region[0],
src_offset[1] + region[1],
src_offset[2] + region[2]};
const size_t dst_min[] = {dst_offset[0], dst_offset[1], dst_offset[2]};
const size_t dst_max[] = {dst_offset[0] + region[0],
dst_offset[1] + region[1],
dst_offset[2] + region[2]};
// Check for overlap
cl_bool overlap = CL_TRUE;
unsigned i;
size_t dst_start = dst_offset[2] * slice_pitch +
dst_offset[1] * row_pitch + dst_offset[0];
size_t dst_end = dst_start + (region[2] * slice_pitch +
region[1] * row_pitch + region[0]);
size_t src_start = src_offset[2] * slice_pitch +
src_offset[1] * row_pitch + src_offset[0];
size_t src_end = src_start + (region[2] * slice_pitch +
region[1] * row_pitch + region[0]);
for (i = 0; i != 3; ++i) {
overlap = overlap && (src_min[i] < dst_max[i]) && (src_max[i] > dst_min[i]);
}
if (!overlap) {
size_t delta_src_x = (src_offset[0] + region[0] > row_pitch) ? src_offset[0] + region[0] - row_pitch : 0;
size_t delta_dst_x = (dst_offset[0] + region[0] > row_pitch) ? dst_offset[0] + region[0] - row_pitch : 0;
if ((delta_src_x > 0 && delta_src_x > dst_offset[0]) ||
(delta_dst_x > 0 && delta_dst_x > src_offset[0])) {
if ((src_start <= dst_start && dst_start < src_end) ||
(dst_start <= src_start && src_start < dst_end))
overlap = CL_TRUE;
}
if (region[2] > 1) {
size_t src_height = slice_pitch / row_pitch;
size_t dst_height = slice_pitch / row_pitch;
size_t delta_src_y = (src_offset[1] + region[1] > src_height) ? src_offset[1] + region[1] - src_height : 0;
size_t delta_dst_y = (dst_offset[1] + region[1] > dst_height) ? dst_offset[1] + region[1] - dst_height : 0;
if ((delta_src_y > 0 && delta_src_y > dst_offset[1]) ||
(delta_dst_y > 0 && delta_dst_y > src_offset[1])) {
if ((src_start <= dst_start && dst_start < src_end) ||
(dst_start <= src_start && src_start < dst_end))
overlap = CL_TRUE;
}
}
}
return overlap;
}
cl_int
clEnqueueCopyBufferRect(cl_command_queue command_queue,
cl_mem src_buffer,
cl_mem dst_buffer,
const size_t *src_origin,
const size_t *dst_origin,
const size_t *region,
size_t src_row_pitch,
size_t src_slice_pitch,
size_t dst_row_pitch,
size_t dst_slice_pitch,
cl_uint num_events_in_wait_list,
const cl_event *event_wait_list,
cl_event *event)
{
cl_int err = CL_SUCCESS;
cl_event e = NULL;
size_t total_size = 0;
cl_int e_status;
do {
if (!CL_OBJECT_IS_COMMAND_QUEUE(command_queue)) {
err = CL_INVALID_COMMAND_QUEUE;
break;
}
if (!CL_OBJECT_IS_MEM(src_buffer)) {
err = CL_INVALID_MEM_OBJECT;
break;
}
if (!CL_OBJECT_IS_MEM(dst_buffer)) {
err = CL_INVALID_MEM_OBJECT;
break;
}
if ((command_queue->ctx != src_buffer->ctx) ||
(command_queue->ctx != dst_buffer->ctx)) {
err = CL_INVALID_CONTEXT;
break;
}
if (!region || region[0] == 0 || region[1] == 0 || region[2] == 0) {
err = CL_INVALID_VALUE;
break;
}
if (src_row_pitch == 0)
src_row_pitch = region[0];
if (src_slice_pitch == 0)
src_slice_pitch = region[1] * src_row_pitch;
if (dst_row_pitch == 0)
dst_row_pitch = region[0];
if (dst_slice_pitch == 0)
dst_slice_pitch = region[1] * dst_row_pitch;
if (src_row_pitch < region[0] ||
dst_row_pitch < region[0]) {
err = CL_INVALID_VALUE;
break;
}
if ((src_slice_pitch < region[1] * src_row_pitch || src_slice_pitch % src_row_pitch != 0) ||
(dst_slice_pitch < region[1] * dst_row_pitch || dst_slice_pitch % dst_row_pitch != 0)) {
err = CL_INVALID_VALUE;
break;
}
total_size = (src_origin[2] + region[2] - 1) * src_slice_pitch +
(src_origin[1] + region[1] - 1) * src_row_pitch + src_origin[0] + region[0];
if (total_size > src_buffer->size) {
err = CL_INVALID_VALUE;
break;
}
total_size = (dst_origin[2] + region[2] - 1) * dst_slice_pitch +
(dst_origin[1] + region[1] - 1) * dst_row_pitch + dst_origin[0] + region[0];
if (total_size > dst_buffer->size) {
err = CL_INVALID_VALUE;
break;
}
if (src_buffer == dst_buffer &&
(src_row_pitch != dst_row_pitch || src_slice_pitch != dst_slice_pitch)) {
err = CL_INVALID_VALUE;
break;
}
if (src_buffer == dst_buffer &&
check_copy_overlap(src_origin, dst_origin, region, src_row_pitch, src_slice_pitch)) {
err = CL_MEM_COPY_OVERLAP;
break;
}
err = cl_event_check_waitlist(num_events_in_wait_list, event_wait_list,
event, command_queue->ctx);
if (err != CL_SUCCESS) {
break;
}
e = cl_event_create(command_queue->ctx, command_queue, num_events_in_wait_list,
event_wait_list, CL_COMMAND_COPY_BUFFER_RECT, &err);
if (err != CL_SUCCESS) {
break;
}
err = cl_mem_copy_buffer_rect(command_queue, e, src_buffer, dst_buffer, src_origin, dst_origin, region,
src_row_pitch, src_slice_pitch, dst_row_pitch, dst_slice_pitch);
if (err != CL_SUCCESS) {
break;
}
/* We will flush the ndrange if no event depend. Else we will add it to queue list.
The finish or Complete status will always be done in queue list. */
e_status = cl_event_is_ready(e);
if (e_status < CL_COMPLETE) { // Error happend, cancel.
err = CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST;
break;
} else if (cl_command_queue_allow_bypass_submit(command_queue) && (e_status == CL_COMPLETE)) {
err = cl_event_exec(e, CL_SUBMITTED, CL_FALSE);
if (err != CL_SUCCESS) {
break;
}
}
cl_command_queue_enqueue_event(command_queue, e);
} while (0);
if (err == CL_SUCCESS && event) {
*event = e;
} else {
cl_event_delete(e);
}
return err;
}
cl_int
clEnqueueFillBuffer(cl_command_queue command_queue,
cl_mem buffer,
const void *pattern,
size_t pattern_size,
size_t offset,
size_t size,
cl_uint num_events_in_wait_list,
const cl_event *event_wait_list,
cl_event *event)
{
cl_int err = CL_SUCCESS;
static size_t valid_sz[] = {1, 2, 4, 8, 16, 32, 64, 128};
int i = 0;
cl_event e = NULL;
cl_int e_status;
do {
if (!CL_OBJECT_IS_COMMAND_QUEUE(command_queue)) {
err = CL_INVALID_COMMAND_QUEUE;
break;
}
if (!CL_OBJECT_IS_BUFFER(buffer)) {
err = CL_INVALID_MEM_OBJECT;
break;
}
if (command_queue->ctx != buffer->ctx) {
err = CL_INVALID_CONTEXT;
break;
}
if (offset + size > buffer->size) {
err = CL_INVALID_VALUE;
break;
}
if (pattern == NULL) {
err = CL_INVALID_VALUE;
break;
}
for (i = 0; i < sizeof(valid_sz) / sizeof(size_t); i++) {
if (valid_sz[i] == pattern_size)
break;
}
if (i == sizeof(valid_sz) / sizeof(size_t)) {
err = CL_INVALID_VALUE;
break;
}
if (offset % pattern_size || size % pattern_size) {
err = CL_INVALID_VALUE;
break;
}
err = cl_event_check_waitlist(num_events_in_wait_list, event_wait_list,
event, command_queue->ctx);
if (err != CL_SUCCESS) {
break;
}
e = cl_event_create(command_queue->ctx, command_queue, num_events_in_wait_list,
event_wait_list, CL_COMMAND_FILL_BUFFER, &err);
if (err != CL_SUCCESS) {
break;
}
err = cl_mem_fill(command_queue, e, pattern, pattern_size, buffer, offset, size);
if (err) {
break;
}
/* We will flush the ndrange if no event depend. Else we will add it to queue list.
The finish or Complete status will always be done in queue list. */
e_status = cl_event_is_ready(e);
if (e_status < CL_COMPLETE) { // Error happend, cancel.
err = CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST;
break;
}
err = cl_event_exec(e, (cl_command_queue_allow_bypass_submit(command_queue) && (e_status == CL_COMPLETE)) ? CL_SUBMITTED : CL_QUEUED, CL_FALSE);
if (err != CL_SUCCESS) {
break;
}
cl_command_queue_enqueue_event(command_queue, e);
} while (0);
if (err == CL_SUCCESS && event) {
*event = e;
} else {
cl_event_delete(e);
}
return err;
}
cl_int
clEnqueueMigrateMemObjects(cl_command_queue command_queue,
cl_uint num_mem_objects,
const cl_mem *mem_objects,
cl_mem_migration_flags flags,
cl_uint num_events_in_wait_list,
const cl_event *event_wait_list,
cl_event *event)
{
/* So far, we just support 1 device and no subdevice. So all the command queues
belong to the small context. There is no need to migrate the mem objects by now. */
cl_int err = CL_SUCCESS;
cl_event e = NULL;
cl_int e_status;
cl_uint i = 0;
do {
if (!flags & CL_MIGRATE_MEM_OBJECT_HOST) {
if (!CL_OBJECT_IS_COMMAND_QUEUE(command_queue)) {
err = CL_INVALID_COMMAND_QUEUE;
break;
}
}
if (num_mem_objects == 0 || mem_objects == NULL) {
err = CL_INVALID_VALUE;
break;
}
if (flags && flags & ~(CL_MIGRATE_MEM_OBJECT_HOST | CL_MIGRATE_MEM_OBJECT_CONTENT_UNDEFINED)) {
err = CL_INVALID_VALUE;
break;
}
for (i = 0; i < num_mem_objects; i++) {
if (!CL_OBJECT_IS_MEM(mem_objects[i])) {
err = CL_INVALID_MEM_OBJECT;
break;
}
if (mem_objects[i]->ctx != command_queue->ctx) {
err = CL_INVALID_CONTEXT;
break;
}
}
if (err != CL_SUCCESS) {
break;
}
err = cl_event_check_waitlist(num_events_in_wait_list, event_wait_list,
event, command_queue->ctx);
if (err != CL_SUCCESS) {
break;
}
e = cl_event_create(command_queue->ctx, command_queue, num_events_in_wait_list,
event_wait_list, CL_COMMAND_MIGRATE_MEM_OBJECTS, &err);
if (err != CL_SUCCESS) {
break;
}
/* Noting to do now, just enqueue a event. */
e->exec_data.type = EnqueueMigrateMemObj;
/* We will flush the ndrange if no event depend. Else we will add it to queue list.
The finish or Complete status will always be done in queue list. */
e_status = cl_event_is_ready(e);
if (e_status < CL_COMPLETE) { // Error happend, cancel.
err = CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST;
break;
}
err = cl_event_exec(e, (cl_command_queue_allow_bypass_submit(command_queue) && (e_status == CL_COMPLETE)) ? CL_SUBMITTED : CL_QUEUED, CL_FALSE);
if (err != CL_SUCCESS) {
break;
}
cl_command_queue_enqueue_event(command_queue, e);
} while (0);
if (err == CL_SUCCESS && event) {
*event = e;
} else {
cl_event_delete(e);
}
return err;
}
/************************************ Images *********************************************/
static cl_int
check_image_region(struct _cl_mem_image *image, const size_t *pregion, size_t *region)
{
if (pregion == NULL) {
return CL_INVALID_VALUE;
}
if (image->image_type == CL_MEM_OBJECT_IMAGE1D_ARRAY) {
region[0] = pregion[0];
region[1] = 1;
region[2] = pregion[1];
} else {
region[0] = pregion[0];
region[1] = pregion[1];
region[2] = pregion[2];
}
if ((region[0] == 0) || (region[1] == 0) || (region[2] == 0)) {
return CL_INVALID_VALUE;
}
return CL_SUCCESS;
}
static cl_int
check_image_origin(struct _cl_mem_image *image, const size_t *porigin, size_t *origin)
{
if (porigin == NULL) {
return CL_INVALID_VALUE;
}
if (image->image_type == CL_MEM_OBJECT_IMAGE1D_ARRAY) {
origin[0] = porigin[0];
origin[1] = 0;
origin[2] = porigin[1];
} else {
origin[0] = porigin[0];
origin[1] = porigin[1];
origin[2] = porigin[2];
}
return CL_SUCCESS;
}
static void *
clEnqueueMapImageByKernel(cl_command_queue command_queue,
cl_mem mem,
cl_bool blocking_map,
cl_map_flags map_flags,
const size_t *porigin,
const size_t *pregion,
size_t *image_row_pitch,
size_t *image_slice_pitch,
cl_uint num_events_in_wait_list,
const cl_event *event_wait_list,
cl_event *event,
cl_int *errcode_ret)
{
cl_int err = CL_SUCCESS;
void *ptr = NULL;
void *mem_ptr = NULL;
struct _cl_mem_image *image = NULL;
size_t region[3], copy_origin[3];
size_t origin[3], copy_region[3];
size_t offset = 0;
size_t buf_size = 0;
image = cl_mem_image(mem);
err = check_image_region(image, pregion, region);
if (err != CL_SUCCESS && errcode_ret) {
*errcode_ret = err;
return NULL;
}
err = check_image_origin(image, porigin, origin);
if (err != CL_SUCCESS && errcode_ret) {
*errcode_ret = err;
return NULL;
}
if (image->tmp_ker_buf)
clReleaseMemObject(image->tmp_ker_buf);
if (mem->flags & CL_MEM_USE_HOST_PTR) {
buf_size = image->w * image->h * image->depth * image->bpp;
memset(copy_origin, 0, sizeof(size_t) * 3);
copy_region[0] = image->w;
copy_region[1] = image->h;
copy_region[2] = image->depth;
image->tmp_ker_buf =
clCreateBuffer(command_queue->ctx, CL_MEM_USE_HOST_PTR, mem->size, mem->host_ptr, &err);
} else {
buf_size = region[0] * region[1] * region[2] * image->bpp;
memcpy(copy_origin, origin, sizeof(size_t) * 3);
memcpy(copy_region, region, sizeof(size_t) * 3);
image->tmp_ker_buf =
clCreateBuffer(command_queue->ctx, CL_MEM_ALLOC_HOST_PTR, buf_size, NULL, &err);
}
if ((image->tmp_ker_buf == NULL || err != CL_SUCCESS) && errcode_ret) {
image->tmp_ker_buf = NULL;
*errcode_ret = err;
return NULL;
}
cl_event e;
err = clEnqueueCopyImageToBuffer(command_queue, mem, image->tmp_ker_buf, copy_origin,
copy_region, 0, num_events_in_wait_list, event_wait_list, &e);
if (err != CL_SUCCESS && errcode_ret) {
clReleaseMemObject(image->tmp_ker_buf);
clReleaseEvent(e);
image->tmp_ker_buf = NULL;
*errcode_ret = err;
return NULL;
}
if (mem->flags & CL_MEM_USE_HOST_PTR) {
if (image_slice_pitch)
*image_slice_pitch = image->host_slice_pitch;
if (image_row_pitch)
*image_row_pitch = image->host_row_pitch;
offset = image->bpp * origin[0] + image->host_row_pitch * origin[1] +
image->host_slice_pitch * origin[2];
} else {
if (image_slice_pitch)
*image_slice_pitch = (image->image_type == CL_MEM_OBJECT_IMAGE2D) ?
image->slice_pitch : region[0] * region[1] * image->bpp;
if (image_row_pitch)
*image_row_pitch = region[0] * image->bpp;
}
ptr = clEnqueueMapBuffer(command_queue, image->tmp_ker_buf, blocking_map, map_flags, 0,
buf_size, 1, &e, event, &err);
if (err != CL_SUCCESS && errcode_ret) {
clReleaseMemObject(image->tmp_ker_buf);
clReleaseEvent(e);
image->tmp_ker_buf = NULL;
*errcode_ret = err;
return NULL;
}
err = cl_mem_record_map_mem_for_kernel(mem, ptr, &mem_ptr, offset, 0, origin, region,
image->tmp_ker_buf, (map_flags & (CL_MAP_WRITE | CL_MAP_WRITE_INVALIDATE_REGION)) ? 1 : 0);
image->tmp_ker_buf = NULL;
assert(err == CL_SUCCESS); // Easy way, do not use unmap to handle error.
if (errcode_ret)
*errcode_ret = err;
clReleaseEvent(e);
return mem_ptr;
}
void *
clEnqueueMapImage(cl_command_queue command_queue,
cl_mem mem,
cl_bool blocking_map,
cl_map_flags map_flags,
const size_t *porigin,
const size_t *pregion,
size_t *image_row_pitch,
size_t *image_slice_pitch,
cl_uint num_events_in_wait_list,
const cl_event *event_wait_list,
cl_event *event,
cl_int *errcode_ret)
{
cl_int err = CL_SUCCESS;
void *ptr = NULL;
void *mem_ptr = NULL;
size_t offset = 0;
struct _cl_mem_image *image = NULL;
cl_int e_status;
enqueue_data *data = NULL;
size_t region[3];
size_t origin[3];
cl_event e = NULL;
do {
if (!CL_OBJECT_IS_COMMAND_QUEUE(command_queue)) {
err = CL_INVALID_COMMAND_QUEUE;
break;
}
if (!CL_OBJECT_IS_IMAGE(mem)) {
err = CL_INVALID_MEM_OBJECT;
break;
}
image = cl_mem_image(mem);
err = check_image_region(image, pregion, region);
if (err != CL_SUCCESS) {
break;
}
err = check_image_origin(image, porigin, origin);
if (err != CL_SUCCESS) {
break;
}
if (command_queue->ctx != mem->ctx) {
err = CL_INVALID_CONTEXT;
break;
}
if (origin[0] + region[0] > image->w ||
origin[1] + region[1] > image->h ||
origin[2] + region[2] > image->depth) {
err = CL_INVALID_VALUE;
break;
}
if (!image_row_pitch || (image->slice_pitch && !image_slice_pitch)) {
err = CL_INVALID_VALUE;
break;
}
if ((map_flags & CL_MAP_READ &&
mem->flags & (CL_MEM_HOST_WRITE_ONLY | CL_MEM_HOST_NO_ACCESS)) ||
(map_flags & (CL_MAP_WRITE | CL_MAP_WRITE_INVALIDATE_REGION) &&
mem->flags & (CL_MEM_HOST_READ_ONLY | CL_MEM_HOST_NO_ACCESS))) {
err = CL_INVALID_OPERATION;
break;
}
if (CL_OBJECT_IS_IMAGE(mem) && cl_mem_image(mem)->is_ker_copy) {
return clEnqueueMapImageByKernel(command_queue, mem, blocking_map, map_flags, origin, region,
image_row_pitch, image_slice_pitch, num_events_in_wait_list, event_wait_list,
event, errcode_ret);
}
err = cl_event_check_waitlist(num_events_in_wait_list, event_wait_list,
event, command_queue->ctx);
if (err != CL_SUCCESS) {
break;
}
e = cl_event_create(command_queue->ctx, command_queue, num_events_in_wait_list,
event_wait_list, CL_COMMAND_MAP_IMAGE, &err);
if (err != CL_SUCCESS) {
break;
}
if (blocking_map) {
err = cl_event_wait_for_event_ready(e);
if (err != CL_SUCCESS)
break;
/* Blocking call API is a sync point of flush. */
err = cl_command_queue_wait_flush(command_queue);
if (err != CL_SUCCESS) {
break;
}
}
e_status = cl_event_is_ready(e);
if (e_status < CL_COMPLETE) {
err = CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST;
break;
}
data = &e->exec_data;
data->type = EnqueueMapImage;
data->mem_obj = mem;
data->origin[0] = origin[0];
data->origin[1] = origin[1];
data->origin[2] = origin[2];
data->region[0] = region[0];
data->region[1] = region[1];
data->region[2] = region[2];
data->ptr = ptr;
data->unsync_map = 1;
if (map_flags & (CL_MAP_WRITE | CL_MAP_WRITE_INVALIDATE_REGION))
data->write_map = 1;
if (cl_command_queue_allow_bypass_submit(command_queue) && (e_status == CL_COMPLETE)) {
// Sync mode, no need to queue event.
err = cl_event_exec(e, CL_COMPLETE, CL_FALSE);
if (err != CL_SUCCESS) {
break;
}
} else {
err = cl_event_exec(e, CL_SUBMITTED, CL_TRUE); // Submit to get the address.
if (err != CL_SUCCESS) {
break;
}
cl_command_queue_enqueue_event(command_queue, e);
if (blocking_map) {
cl_event_wait_for_events_list(1, &e);
}
}
ptr = data->ptr;
assert(ptr);
/* Store and write back map info. */
if (mem->flags & CL_MEM_USE_HOST_PTR) {
if (image_slice_pitch)
*image_slice_pitch = image->host_slice_pitch;
*image_row_pitch = image->host_row_pitch;
offset = image->bpp * origin[0] + image->host_row_pitch * origin[1] +
image->host_slice_pitch * origin[2];
} else {
if (image_slice_pitch)
*image_slice_pitch = image->slice_pitch;
if (image->image_type == CL_MEM_OBJECT_IMAGE1D_ARRAY)
*image_row_pitch = image->slice_pitch;
else
*image_row_pitch = image->row_pitch;
offset = image->bpp * origin[0] + image->row_pitch * origin[1] + image->slice_pitch * origin[2];
}
err = cl_mem_record_map_mem(mem, ptr, &mem_ptr, offset, 0, origin, region);
assert(err == CL_SUCCESS); // Easy way, do not use unmap to handle error.
} while (0);
if (err != CL_SUCCESS) {
if (e) {
cl_event_delete(e);
e = NULL;
}
assert(ptr == NULL);
}
if (err == CL_SUCCESS && event) {
*event = e;
} else {
cl_event_delete(e);
}
if (errcode_ret)
*errcode_ret = err;
return mem_ptr;
}
static cl_int
clEnqueueReadImageByKernel(cl_command_queue command_queue,
cl_mem mem,
cl_bool blocking_read,
const size_t *porigin,
const size_t *pregion,
size_t row_pitch,
size_t slice_pitch,
void *ptr,
cl_uint num_events_in_wait_list,
const cl_event *event_wait_list,
cl_event *event)
{
cl_int err = CL_SUCCESS;
struct _cl_mem_image *image = NULL;
size_t region[3];
size_t origin[3];
image = cl_mem_image(mem);
err = check_image_region(image, pregion, region);
if (err != CL_SUCCESS)
return err;
err = check_image_origin(image, porigin, origin);
if (err != CL_SUCCESS)
return err;
if (image->tmp_ker_buf)
clReleaseMemObject(image->tmp_ker_buf);
size_t buf_size = region[0] * region[1] * region[2] * image->bpp;
image->tmp_ker_buf = clCreateBuffer(command_queue->ctx, CL_MEM_USE_HOST_PTR,
buf_size, ptr, &err);
if (image->tmp_ker_buf == NULL || err != CL_SUCCESS) {
image->tmp_ker_buf = NULL;
return err;
}
cl_event e;
err = clEnqueueCopyImageToBuffer(command_queue, mem, image->tmp_ker_buf, origin,
region, 0, num_events_in_wait_list, event_wait_list, &e);
if (err != CL_SUCCESS) {
clReleaseMemObject(image->tmp_ker_buf);
clReleaseEvent(e);
image->tmp_ker_buf = NULL;
return err;
}
err = clEnqueueReadBuffer(command_queue, image->tmp_ker_buf, blocking_read, 0,
buf_size, ptr, 1, &e, event);
clReleaseEvent(e);
return err;
}
cl_int
clEnqueueReadImage(cl_command_queue command_queue,
cl_mem mem,
cl_bool blocking_read,
const size_t *porigin,
const size_t *pregion,
size_t row_pitch,
size_t slice_pitch,
void *ptr,
cl_uint num_events_in_wait_list,
const cl_event *event_wait_list,
cl_event *event)
{
cl_int err = CL_SUCCESS;
struct _cl_mem_image *image = NULL;
enqueue_data *data = NULL;
cl_int e_status;
size_t region[3];
size_t origin[3];
cl_event e = NULL;
do {
if (!CL_OBJECT_IS_COMMAND_QUEUE(command_queue)) {
err = CL_INVALID_COMMAND_QUEUE;
break;
}
if (!CL_OBJECT_IS_IMAGE(mem)) {
err = CL_INVALID_MEM_OBJECT;
break;
}
image = cl_mem_image(mem);
err = check_image_region(image, pregion, region);
if (err != CL_SUCCESS) {
break;
}
err = check_image_origin(image, porigin, origin);
if (err != CL_SUCCESS) {
break;
}
if (command_queue->ctx != mem->ctx) {
err = CL_INVALID_CONTEXT;
break;
}
if (origin[0] + region[0] > image->w ||
origin[1] + region[1] > image->h ||
origin[2] + region[2] > image->depth) {
err = CL_INVALID_VALUE;
break;
}
if (!row_pitch) {
row_pitch = image->bpp * region[0];
} else if (row_pitch < image->bpp * region[0]) {
err = CL_INVALID_VALUE;
break;
}
if (image->slice_pitch) {
if (!slice_pitch) {
slice_pitch = row_pitch * region[1];
} else if (slice_pitch < row_pitch * region[1]) {
err = CL_INVALID_VALUE;
break;
}
} else if (slice_pitch) {
err = CL_INVALID_VALUE;
break;
}
if (!ptr) {
err = CL_INVALID_VALUE;
break;
}
if (mem->flags & (CL_MEM_HOST_WRITE_ONLY | CL_MEM_HOST_NO_ACCESS)) {
err = CL_INVALID_OPERATION;
break;
}
if (image->is_ker_copy) {
return clEnqueueReadImageByKernel(command_queue, mem, blocking_read, origin,
region, row_pitch, slice_pitch, ptr, num_events_in_wait_list, event_wait_list, event);
}
err = cl_event_check_waitlist(num_events_in_wait_list, event_wait_list,
event, command_queue->ctx);
if (err != CL_SUCCESS) {
break;
}
e = cl_event_create(command_queue->ctx, command_queue, num_events_in_wait_list,
event_wait_list, CL_COMMAND_READ_IMAGE, &err);
if (err != CL_SUCCESS) {
break;
}
if (blocking_read) {
err = cl_event_wait_for_event_ready(e);
if (err != CL_SUCCESS)
break;
/* Blocking call API is a sync point of flush. */
err = cl_command_queue_wait_flush(command_queue);
if (err != CL_SUCCESS) {
break;
}
}
e_status = cl_event_is_ready(e);
if (e_status < CL_COMPLETE) {
err = CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST;
break;
}
data = &e->exec_data;
data->type = EnqueueReadImage;
data->mem_obj = mem;
data->ptr = ptr;
data->origin[0] = origin[0];
data->origin[1] = origin[1];
data->origin[2] = origin[2];
data->region[0] = region[0];
data->region[1] = region[1];
data->region[2] = region[2];
data->row_pitch = row_pitch;
data->slice_pitch = slice_pitch;
if (cl_command_queue_allow_bypass_submit(command_queue) && (e_status == CL_COMPLETE)) {
// Sync mode, no need to queue event.
err = cl_event_exec(e, CL_COMPLETE, CL_FALSE);
if (err != CL_SUCCESS) {
break;
}
} else {
err = cl_event_exec(e, CL_QUEUED, CL_FALSE);
if (err != CL_SUCCESS) {
break;
}
cl_command_queue_enqueue_event(command_queue, e);
if (blocking_read) {
cl_event_wait_for_events_list(1, &e);
}
}
} while (0);
if (err == CL_SUCCESS && event) {
*event = e;
} else {
cl_event_delete(e);
}
return err;
}
static cl_int
clEnqueueWriteImageByKernel(cl_command_queue command_queue,
cl_mem mem,
cl_bool blocking_write,
const size_t *porigin,
const size_t *pregion,
size_t row_pitch,
size_t slice_pitch,
const void *ptr,
cl_uint num_events_in_wait_list,
const cl_event *event_wait_list,
cl_event *event)
{
cl_int err = CL_SUCCESS;
struct _cl_mem_image *image = NULL;
size_t region[3];
size_t origin[3];
image = cl_mem_image(mem);
err = check_image_region(image, pregion, region);
if (err != CL_SUCCESS)
return err;
err = check_image_origin(image, porigin, origin);
if (err != CL_SUCCESS)
return err;
if (image->tmp_ker_buf)
clReleaseMemObject(image->tmp_ker_buf);
size_t buf_size = region[0] * region[1] * region[2] * image->bpp;
image->tmp_ker_buf = clCreateBuffer(command_queue->ctx, CL_MEM_USE_HOST_PTR, buf_size, (void*)ptr, &err);
if (image->tmp_ker_buf == NULL || err != CL_SUCCESS) {
image->tmp_ker_buf = NULL;
return err;
}
err = clEnqueueCopyBufferToImage(command_queue, image->tmp_ker_buf, mem, 0, origin, region,
num_events_in_wait_list, event_wait_list, event);
if (blocking_write)
err = clFinish(command_queue);
return err;
}
cl_int
clEnqueueWriteImage(cl_command_queue command_queue,
cl_mem mem,
cl_bool blocking_write,
const size_t *porigin,
const size_t *pregion,
size_t row_pitch,
size_t slice_pitch,
const void *ptr,
cl_uint num_events_in_wait_list,
const cl_event *event_wait_list,
cl_event *event)
{
cl_int err = CL_SUCCESS;
struct _cl_mem_image *image = NULL;
enqueue_data *data = NULL;
cl_int e_status;
size_t region[3];
size_t origin[3];
cl_event e = NULL;
do {
if (!CL_OBJECT_IS_COMMAND_QUEUE(command_queue)) {
err = CL_INVALID_COMMAND_QUEUE;
break;
}
if (!CL_OBJECT_IS_IMAGE(mem)) {
err = CL_INVALID_MEM_OBJECT;
break;
}
image = cl_mem_image(mem);
err = check_image_region(image, pregion, region);
if (err != CL_SUCCESS) {
break;
}
err = check_image_origin(image, porigin, origin);
if (err != CL_SUCCESS) {
break;
}
if (command_queue->ctx != mem->ctx) {
err = CL_INVALID_CONTEXT;
break;
}
if (origin[0] + region[0] > image->w ||
origin[1] + region[1] > image->h ||
origin[2] + region[2] > image->depth) {
err = CL_INVALID_VALUE;
break;
}
if (!row_pitch) {
row_pitch = image->bpp * region[0];
} else if (row_pitch < image->bpp * region[0]) {
err = CL_INVALID_VALUE;
break;
}
if (image->slice_pitch) {
if (!slice_pitch) {
slice_pitch = row_pitch * region[1];
} else if (slice_pitch < row_pitch * region[1]) {
err = CL_INVALID_VALUE;
break;
}
} else if (slice_pitch) {
err = CL_INVALID_VALUE;
break;
}
if (!ptr) {
err = CL_INVALID_VALUE;
break;
}
if (mem->flags & (CL_MEM_HOST_READ_ONLY | CL_MEM_HOST_NO_ACCESS)) {
err = CL_INVALID_OPERATION;
break;
}
if (image->is_ker_copy) {
return clEnqueueWriteImageByKernel(command_queue, mem, blocking_write, origin,
region, row_pitch, slice_pitch, ptr, num_events_in_wait_list, event_wait_list, event);
}
err = cl_event_check_waitlist(num_events_in_wait_list, event_wait_list,
event, command_queue->ctx);
if (err != CL_SUCCESS) {
break;
}
e = cl_event_create(command_queue->ctx, command_queue, num_events_in_wait_list,
event_wait_list, CL_COMMAND_WRITE_IMAGE, &err);
if (err != CL_SUCCESS) {
break;
}
if (blocking_write) {
err = cl_event_wait_for_event_ready(e);
if (err != CL_SUCCESS)
break;
/* Blocking call API is a sync point of flush. */
err = cl_command_queue_wait_flush(command_queue);
if (err != CL_SUCCESS) {
break;
}
}
e_status = cl_event_is_ready(e);
if (e_status < CL_COMPLETE) {
err = CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST;
break;
}
data = &e->exec_data;
data->type = EnqueueWriteImage;
data->mem_obj = mem;
data->const_ptr = ptr;
data->origin[0] = origin[0];
data->origin[1] = origin[1];
data->origin[2] = origin[2];
data->region[0] = region[0];
data->region[1] = region[1];
data->region[2] = region[2];
data->row_pitch = row_pitch;
data->slice_pitch = slice_pitch;
if (cl_command_queue_allow_bypass_submit(command_queue) && (e_status == CL_COMPLETE)) {
// Sync mode, no need to queue event.
err = cl_event_exec(e, CL_COMPLETE, CL_FALSE);
if (err != CL_SUCCESS) {
break;
}
} else {
err = cl_event_exec(e, CL_QUEUED, CL_FALSE);
if (err != CL_SUCCESS) {
break;
}
cl_command_queue_enqueue_event(command_queue, e);
if (blocking_write) {
cl_event_wait_for_events_list(1, &e);
}
}
} while (0);
if (err == CL_SUCCESS && event) {
*event = e;
} else {
cl_event_delete(e);
}
return err;
}
cl_int
clEnqueueCopyImage(cl_command_queue command_queue,
cl_mem src_mem,
cl_mem dst_mem,
const size_t *psrc_origin,
const size_t *pdst_origin,
const size_t *pregion,
cl_uint num_events_in_wait_list,
const cl_event *event_wait_list,
cl_event *event)
{
cl_int err = CL_SUCCESS;
cl_bool overlap = CL_TRUE;
cl_int i = 0;
cl_event e = NULL;
struct _cl_mem_image *src_image = NULL;
struct _cl_mem_image *dst_image = NULL;
size_t region[3];
size_t src_origin[3];
size_t dst_origin[3];
cl_int e_status;
do {
if (!CL_OBJECT_IS_COMMAND_QUEUE(command_queue)) {
err = CL_INVALID_COMMAND_QUEUE;
break;
}
if (!CL_OBJECT_IS_IMAGE(src_mem)) {
err = CL_INVALID_MEM_OBJECT;
break;
}
if (!CL_OBJECT_IS_IMAGE(dst_mem)) {
err = CL_INVALID_MEM_OBJECT;
break;
}
src_image = cl_mem_image(src_mem);
dst_image = cl_mem_image(dst_mem);
err = check_image_region(src_image, pregion, region);
if (err != CL_SUCCESS) {
break;
}
err = check_image_origin(src_image, psrc_origin, src_origin);
if (err != CL_SUCCESS) {
break;
}
err = check_image_origin(dst_image, pdst_origin, dst_origin);
if (err != CL_SUCCESS) {
break;
}
if (command_queue->ctx != src_mem->ctx ||
command_queue->ctx != dst_mem->ctx) {
err = CL_INVALID_CONTEXT;
break;
}
if (src_image->fmt.image_channel_order != dst_image->fmt.image_channel_order ||
src_image->fmt.image_channel_data_type != dst_image->fmt.image_channel_data_type) {
err = CL_IMAGE_FORMAT_MISMATCH;
break;
}
if (src_origin[0] + region[0] > src_image->w ||
src_origin[1] + region[1] > src_image->h ||
src_origin[2] + region[2] > src_image->depth) {
err = CL_INVALID_VALUE;
break;
}
if (dst_origin[0] + region[0] > dst_image->w ||
dst_origin[1] + region[1] > dst_image->h ||
dst_origin[2] + region[2] > dst_image->depth) {
err = CL_INVALID_VALUE;
break;
}
if ((src_image->image_type == CL_MEM_OBJECT_IMAGE2D && (src_origin[2] != 0 || region[2] != 1)) ||
(dst_image->image_type == CL_MEM_OBJECT_IMAGE2D && (dst_origin[2] != 0 || region[2] != 1))) {
err = CL_INVALID_VALUE;
break;
}
if (src_image == dst_image) {
for (i = 0; i < 3; i++) {
overlap = overlap && (src_origin[i] < dst_origin[i] + region[i]) &&
(dst_origin[i] < src_origin[i] + region[i]);
}
if (overlap == CL_TRUE) {
err = CL_MEM_COPY_OVERLAP;
break;
}
}
err = cl_event_check_waitlist(num_events_in_wait_list, event_wait_list,
event, command_queue->ctx);
if (err != CL_SUCCESS) {
break;
}
e = cl_event_create(command_queue->ctx, command_queue, num_events_in_wait_list,
event_wait_list, CL_COMMAND_COPY_IMAGE, &err);
if (err != CL_SUCCESS) {
break;
}
err = cl_mem_kernel_copy_image(command_queue, e, src_image, dst_image,
src_origin, dst_origin, region);
if (err != CL_SUCCESS) {
break;
}
/* We will flush the ndrange if no event depend. Else we will add it to queue list.
The finish or Complete status will always be done in queue list. */
e_status = cl_event_is_ready(e);
if (e_status < CL_COMPLETE) { // Error happend, cancel.
err = CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST;
break;
}
err = cl_event_exec(e, (cl_command_queue_allow_bypass_submit(command_queue) && (e_status == CL_COMPLETE)) ? CL_SUBMITTED : CL_QUEUED, CL_FALSE);
if (err != CL_SUCCESS) {
break;
}
cl_command_queue_enqueue_event(command_queue, e);
} while (0);
if (err == CL_SUCCESS && event) {
*event = e;
} else {
cl_event_delete(e);
}
return err;
}
cl_int
clEnqueueCopyImageToBuffer(cl_command_queue command_queue,
cl_mem src_mem,
cl_mem dst_buffer,
const size_t *psrc_origin,
const size_t *pregion,
size_t dst_offset,
cl_uint num_events_in_wait_list,
const cl_event *event_wait_list,
cl_event *event)
{
cl_int err = CL_SUCCESS;
struct _cl_mem_image *src_image = NULL;
size_t region[3];
size_t src_origin[3];
cl_event e = NULL;
cl_int e_status;
do {
if (!CL_OBJECT_IS_COMMAND_QUEUE(command_queue)) {
err = CL_INVALID_COMMAND_QUEUE;
break;
}
if (!CL_OBJECT_IS_IMAGE(src_mem)) {
err = CL_INVALID_MEM_OBJECT;
break;
}
if (!CL_OBJECT_IS_BUFFER(dst_buffer)) {
err = CL_INVALID_MEM_OBJECT;
break;
}
src_image = cl_mem_image(src_mem);
err = check_image_region(src_image, pregion, region);
if (err != CL_SUCCESS) {
break;
}
err = check_image_origin(src_image, psrc_origin, src_origin);
if (err != CL_SUCCESS) {
break;
}
if (command_queue->ctx != src_mem->ctx ||
command_queue->ctx != dst_buffer->ctx) {
err = CL_INVALID_CONTEXT;
break;
}
if (dst_offset + region[0] * region[1] * region[2] * src_image->bpp > dst_buffer->size) {
err = CL_INVALID_VALUE;
break;
}
if (src_origin[0] + region[0] > src_image->w ||
src_origin[1] + region[1] > src_image->h ||
src_origin[2] + region[2] > src_image->depth) {
err = CL_INVALID_VALUE;
break;
}
if (src_image->image_type == CL_MEM_OBJECT_IMAGE2D && (src_origin[2] != 0 || region[2] != 1)) {
err = CL_INVALID_VALUE;
break;
}
err = cl_event_check_waitlist(num_events_in_wait_list, event_wait_list,
event, command_queue->ctx);
if (err != CL_SUCCESS) {
break;
}
e = cl_event_create(command_queue->ctx, command_queue, num_events_in_wait_list,
event_wait_list, CL_COMMAND_COPY_IMAGE_TO_BUFFER, &err);
if (err != CL_SUCCESS) {
break;
}
err = cl_mem_copy_image_to_buffer(command_queue, e, src_image, dst_buffer,
src_origin, dst_offset, region);
if (err != CL_SUCCESS) {
break;
}
/* We will flush the ndrange if no event depend. Else we will add it to queue list.
The finish or Complete status will always be done in queue list. */
e_status = cl_event_is_ready(e);
if (e_status < CL_COMPLETE) { // Error happend, cancel.
err = CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST;
break;
}
err = cl_event_exec(e, (cl_command_queue_allow_bypass_submit(command_queue) && (e_status == CL_COMPLETE)) ? CL_SUBMITTED : CL_QUEUED, CL_FALSE);
if (err != CL_SUCCESS) {
break;
}
cl_command_queue_enqueue_event(command_queue, e);
} while (0);
if (err == CL_SUCCESS && event) {
*event = e;
} else {
cl_event_delete(e);
}
return err;
}
cl_int
clEnqueueCopyBufferToImage(cl_command_queue command_queue,
cl_mem src_buffer,
cl_mem dst_mem,
size_t src_offset,
const size_t *pdst_origin,
const size_t *pregion,
cl_uint num_events_in_wait_list,
const cl_event *event_wait_list,
cl_event *event)
{
cl_int err = CL_SUCCESS;
struct _cl_mem_image *dst_image = NULL;
size_t region[3];
size_t dst_origin[3];
cl_event e = NULL;
cl_int e_status;
do {
if (!CL_OBJECT_IS_COMMAND_QUEUE(command_queue)) {
err = CL_INVALID_COMMAND_QUEUE;
break;
}
if (!CL_OBJECT_IS_BUFFER(src_buffer)) {
err = CL_INVALID_MEM_OBJECT;
break;
}
if (!CL_OBJECT_IS_IMAGE(dst_mem)) {
err = CL_INVALID_MEM_OBJECT;
break;
}
dst_image = cl_mem_image(dst_mem);
err = check_image_region(dst_image, pregion, region);
if (err != CL_SUCCESS) {
break;
}
err = check_image_origin(dst_image, pdst_origin, dst_origin);
if (err != CL_SUCCESS) {
break;
}
if (command_queue->ctx != src_buffer->ctx ||
command_queue->ctx != dst_mem->ctx) {
err = CL_INVALID_CONTEXT;
break;
}
if (src_offset + region[0] * region[1] * region[2] * dst_image->bpp > src_buffer->size) {
err = CL_INVALID_VALUE;
break;
}
if (dst_origin[0] + region[0] > dst_image->w ||
dst_origin[1] + region[1] > dst_image->h ||
dst_origin[2] + region[2] > dst_image->depth) {
err = CL_INVALID_VALUE;
break;
}
if (dst_image->image_type == CL_MEM_OBJECT_IMAGE2D && (dst_origin[2] != 0 || region[2] != 1)) {
err = CL_INVALID_VALUE;
break;
}
err = cl_event_check_waitlist(num_events_in_wait_list, event_wait_list,
event, command_queue->ctx);
if (err != CL_SUCCESS) {
break;
}
e = cl_event_create(command_queue->ctx, command_queue, num_events_in_wait_list,
event_wait_list, CL_COMMAND_COPY_BUFFER_TO_IMAGE, &err);
if (err != CL_SUCCESS) {
break;
}
err = cl_mem_copy_buffer_to_image(command_queue, e, src_buffer, dst_image,
src_offset, dst_origin, region);
if (err != CL_SUCCESS) {
break;
}
/* We will flush the ndrange if no event depend. Else we will add it to queue list.
The finish or Complete status will always be done in queue list. */
e_status = cl_event_is_ready(e);
if (e_status < CL_COMPLETE) { // Error happend, cancel.
err = CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST;
break;
}
err = cl_event_exec(e, (cl_command_queue_allow_bypass_submit(command_queue) && (e_status == CL_COMPLETE)) ? CL_SUBMITTED : CL_QUEUED, CL_FALSE);
if (err != CL_SUCCESS) {
break;
}
cl_command_queue_enqueue_event(command_queue, e);
} while (0);
if (err == CL_SUCCESS && event) {
*event = e;
} else {
cl_event_delete(e);
}
return err;
}
cl_int
clEnqueueFillImage(cl_command_queue command_queue,
cl_mem mem,
const void *fill_color,
const size_t *porigin,
const size_t *pregion,
cl_uint num_events_in_wait_list,
const cl_event *event_wait_list,
cl_event *event)
{
cl_int err = CL_SUCCESS;
size_t region[3];
size_t origin[3];
cl_event e = NULL;
struct _cl_mem_image *image = NULL;
cl_int e_status;
do {
if (!CL_OBJECT_IS_COMMAND_QUEUE(command_queue)) {
err = CL_INVALID_COMMAND_QUEUE;
break;
}
if (!CL_OBJECT_IS_IMAGE(mem)) {
err = CL_INVALID_MEM_OBJECT;
break;
}
image = cl_mem_image(mem);
err = check_image_region(image, pregion, region);
if (err != CL_SUCCESS) {
break;
}
err = check_image_origin(image, porigin, origin);
if (err != CL_SUCCESS) {
break;
}
if (command_queue->ctx != mem->ctx) {
err = CL_INVALID_CONTEXT;
break;
}
if (fill_color == NULL) {
err = CL_INVALID_VALUE;
break;
}
if (origin[0] + region[0] > image->w ||
origin[1] + region[1] > image->h ||
origin[2] + region[2] > image->depth) {
err = CL_INVALID_VALUE;
break;
}
if (image->image_type == CL_MEM_OBJECT_IMAGE2D && (origin[2] != 0 || region[2] != 1)) {
err = CL_INVALID_VALUE;
break;
}
if (image->image_type == CL_MEM_OBJECT_IMAGE1D && (origin[2] != 0 || origin[1] != 0 ||
region[2] != 1 || region[1] != 1)) {
err = CL_INVALID_VALUE;
break;
}
err = cl_event_check_waitlist(num_events_in_wait_list, event_wait_list,
event, command_queue->ctx);
if (err != CL_SUCCESS) {
break;
}
e = cl_event_create(command_queue->ctx, command_queue, num_events_in_wait_list,
event_wait_list, CL_COMMAND_FILL_IMAGE, &err);
if (err != CL_SUCCESS) {
break;
}
err = cl_image_fill(command_queue, e, fill_color, image, origin, region);
if (err != CL_SUCCESS) {
break;
}
/* We will flush the ndrange if no event depend. Else we will add it to queue list.
The finish or Complete status will always be done in queue list. */
e_status = cl_event_is_ready(e);
if (e_status < CL_COMPLETE) { // Error happend, cancel.
err = CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST;
break;
}
err = cl_event_exec(e, (cl_command_queue_allow_bypass_submit(command_queue) && (e_status == CL_COMPLETE)) ? CL_SUBMITTED : CL_QUEUED, CL_FALSE);
if (err != CL_SUCCESS) {
break;
}
cl_command_queue_enqueue_event(command_queue, e);
} while (0);
if (err == CL_SUCCESS && event) {
*event = e;
} else {
cl_event_delete(e);
}
return err;
}
cl_int
clRetainMemObject(cl_mem memobj)
{
if (!CL_OBJECT_IS_MEM(memobj)) {
return CL_INVALID_MEM_OBJECT;
}
cl_mem_add_ref(memobj);
return CL_SUCCESS;
}
cl_int
clReleaseMemObject(cl_mem memobj)
{
if (!CL_OBJECT_IS_MEM(memobj)) {
return CL_INVALID_MEM_OBJECT;
}
cl_mem_delete(memobj);
return CL_SUCCESS;
}