st/nine: Add debug warning when application uses sw processing
[mesa.git] / src / gallium / state_trackers / clover / api / memory.cpp
index b6b82f8d4259df9eb5c4d28122971f29eb846338..3ff6ba0e1c505342f773a419a5aac3f3eceb7ad3 100644 (file)
 // OTHER DEALINGS IN THE SOFTWARE.
 //
 
+#include "util/u_math.h"
 #include "api/util.hpp"
 #include "core/memory.hpp"
 #include "core/format.hpp"
 
 using namespace clover;
 
-PUBLIC cl_mem
-clCreateBuffer(cl_context ctx, cl_mem_flags flags, size_t size,
-               void *host_ptr, cl_int *errcode_ret) try {
-   if (!ctx)
-      throw error(CL_INVALID_CONTEXT);
+namespace {
+   const cl_mem_flags dev_access_flags =
+      CL_MEM_READ_WRITE | CL_MEM_WRITE_ONLY | CL_MEM_READ_ONLY;
+   const cl_mem_flags host_ptr_flags =
+      CL_MEM_USE_HOST_PTR | CL_MEM_ALLOC_HOST_PTR | CL_MEM_COPY_HOST_PTR;
+   const cl_mem_flags host_access_flags =
+      CL_MEM_HOST_WRITE_ONLY | CL_MEM_HOST_READ_ONLY | CL_MEM_HOST_NO_ACCESS;
+   const cl_mem_flags all_mem_flags =
+      dev_access_flags | host_ptr_flags | host_access_flags;
+
+   void
+   validate_flags(cl_mem_flags flags, cl_mem_flags valid) {
+      if ((flags & ~valid) ||
+          util_bitcount(flags & dev_access_flags) > 1 ||
+          util_bitcount(flags & host_access_flags) > 1)
+         throw error(CL_INVALID_VALUE);
+
+      if ((flags & CL_MEM_USE_HOST_PTR) &&
+          (flags & (CL_MEM_COPY_HOST_PTR | CL_MEM_ALLOC_HOST_PTR)))
+         throw error(CL_INVALID_VALUE);
+   }
+}
+
+CLOVER_API cl_mem
+clCreateBuffer(cl_context d_ctx, cl_mem_flags d_flags, size_t size,
+               void *host_ptr, cl_int *r_errcode) try {
+   const cl_mem_flags flags = d_flags |
+      (d_flags & dev_access_flags ? 0 : CL_MEM_READ_WRITE);
+   auto &ctx = obj(d_ctx);
+
+   validate_flags(d_flags, all_mem_flags);
 
    if (bool(host_ptr) != bool(flags & (CL_MEM_USE_HOST_PTR |
                                        CL_MEM_COPY_HOST_PTR)))
       throw error(CL_INVALID_HOST_PTR);
 
-   if (!size)
+   if (!size ||
+       size > fold(maximum(), cl_ulong(0),
+                   map(std::mem_fn(&device::max_mem_alloc_size), ctx.devices())
+          ))
       throw error(CL_INVALID_BUFFER_SIZE);
 
-   if (flags & ~(CL_MEM_READ_WRITE | CL_MEM_WRITE_ONLY | CL_MEM_READ_ONLY |
-                 CL_MEM_USE_HOST_PTR | CL_MEM_ALLOC_HOST_PTR |
-                 CL_MEM_COPY_HOST_PTR))
-      throw error(CL_INVALID_VALUE);
-
-   ret_error(errcode_ret, CL_SUCCESS);
-   return new root_buffer(obj(ctx), flags, size, host_ptr);
+   ret_error(r_errcode, CL_SUCCESS);
+   return new root_buffer(ctx, flags, size, host_ptr);
 
 } catch (error &e) {
-   ret_error(errcode_ret, e);
+   ret_error(r_errcode, e);
    return NULL;
 }
 
-PUBLIC cl_mem
-clCreateSubBuffer(cl_mem obj, cl_mem_flags flags, cl_buffer_create_type op,
-                  const void *op_info, cl_int *errcode_ret) try {
-   root_buffer *parent = dynamic_cast<root_buffer *>(obj);
+CLOVER_API cl_mem
+clCreateSubBuffer(cl_mem d_mem, cl_mem_flags d_flags,
+                  cl_buffer_create_type op,
+                  const void *op_info, cl_int *r_errcode) try {
+   auto &parent = obj<root_buffer>(d_mem);
+   const cl_mem_flags flags = d_flags |
+      (d_flags & dev_access_flags ? 0 : parent.flags() & dev_access_flags) |
+      (d_flags & host_access_flags ? 0 : parent.flags() & host_access_flags) |
+      (parent.flags() & host_ptr_flags);
 
-   if (!parent)
-      throw error(CL_INVALID_MEM_OBJECT);
+   validate_flags(d_flags, dev_access_flags | host_access_flags);
 
-   if ((flags & (CL_MEM_USE_HOST_PTR |
-                 CL_MEM_ALLOC_HOST_PTR |
-                 CL_MEM_COPY_HOST_PTR)) ||
-       (~flags & parent->flags() & (CL_MEM_READ_ONLY |
-                                    CL_MEM_WRITE_ONLY)))
+   if (~flags & parent.flags() &
+       ((dev_access_flags & ~CL_MEM_READ_WRITE) | host_access_flags))
       throw error(CL_INVALID_VALUE);
 
    if (op == CL_BUFFER_CREATE_TYPE_REGION) {
-      const cl_buffer_region *reg = (const cl_buffer_region *)op_info;
+      auto reg = reinterpret_cast<const cl_buffer_region *>(op_info);
 
       if (!reg ||
-          reg->origin > parent->size() ||
-          reg->origin + reg->size > parent->size())
+          reg->origin > parent.size() ||
+          reg->origin + reg->size > parent.size())
          throw error(CL_INVALID_VALUE);
 
       if (!reg->size)
          throw error(CL_INVALID_BUFFER_SIZE);
 
-      ret_error(errcode_ret, CL_SUCCESS);
-      return new sub_buffer(*parent, flags, reg->origin, reg->size);
+      ret_error(r_errcode, CL_SUCCESS);
+      return new sub_buffer(parent, flags, reg->origin, reg->size);
 
    } else {
       throw error(CL_INVALID_VALUE);
    }
 
 } catch (error &e) {
-   ret_error(errcode_ret, e);
+   ret_error(r_errcode, e);
    return NULL;
 }
 
-PUBLIC cl_mem
-clCreateImage2D(cl_context d_ctx, cl_mem_flags flags,
+CLOVER_API cl_mem
+clCreateImage2D(cl_context d_ctx, cl_mem_flags d_flags,
                 const cl_image_format *format,
                 size_t width, size_t height, size_t row_pitch,
-                void *host_ptr, cl_int *errcode_ret) try {
+                void *host_ptr, cl_int *r_errcode) try {
+   const cl_mem_flags flags = d_flags |
+      (d_flags & dev_access_flags ? 0 : CL_MEM_READ_WRITE);
    auto &ctx = obj(d_ctx);
 
-   if (flags & ~(CL_MEM_READ_WRITE | CL_MEM_WRITE_ONLY | CL_MEM_READ_ONLY |
-                 CL_MEM_USE_HOST_PTR | CL_MEM_ALLOC_HOST_PTR |
-                 CL_MEM_COPY_HOST_PTR))
-      throw error(CL_INVALID_VALUE);
+   validate_flags(d_flags, all_mem_flags);
+
+   if (!any_of(std::mem_fn(&device::image_support), ctx.devices()))
+      throw error(CL_INVALID_OPERATION);
 
    if (!format)
       throw error(CL_INVALID_IMAGE_FORMAT_DESCRIPTOR);
@@ -115,27 +143,29 @@ clCreateImage2D(cl_context d_ctx, cl_mem_flags flags,
    if (!supported_formats(ctx, CL_MEM_OBJECT_IMAGE2D).count(*format))
       throw error(CL_IMAGE_FORMAT_NOT_SUPPORTED);
 
-   ret_error(errcode_ret, CL_SUCCESS);
+   ret_error(r_errcode, CL_SUCCESS);
    return new image2d(ctx, flags, format, width, height,
                       row_pitch, host_ptr);
 
 } catch (error &e) {
-   ret_error(errcode_ret, e);
+   ret_error(r_errcode, e);
    return NULL;
 }
 
-PUBLIC cl_mem
-clCreateImage3D(cl_context d_ctx, cl_mem_flags flags,
+CLOVER_API cl_mem
+clCreateImage3D(cl_context d_ctx, cl_mem_flags d_flags,
                 const cl_image_format *format,
                 size_t width, size_t height, size_t depth,
                 size_t row_pitch, size_t slice_pitch,
-                void *host_ptr, cl_int *errcode_ret) try {
+                void *host_ptr, cl_int *r_errcode) try {
+   const cl_mem_flags flags = d_flags |
+      (d_flags & dev_access_flags ? 0 : CL_MEM_READ_WRITE);
    auto &ctx = obj(d_ctx);
 
-   if (flags & ~(CL_MEM_READ_WRITE | CL_MEM_WRITE_ONLY | CL_MEM_READ_ONLY |
-                 CL_MEM_USE_HOST_PTR | CL_MEM_ALLOC_HOST_PTR |
-                 CL_MEM_COPY_HOST_PTR))
-      throw error(CL_INVALID_VALUE);
+   validate_flags(d_flags, all_mem_flags);
+
+   if (!any_of(std::mem_fn(&device::image_support), ctx.devices()))
+      throw error(CL_INVALID_OPERATION);
 
    if (!format)
       throw error(CL_INVALID_IMAGE_FORMAT_DESCRIPTOR);
@@ -150,36 +180,34 @@ clCreateImage3D(cl_context d_ctx, cl_mem_flags flags,
    if (!supported_formats(ctx, CL_MEM_OBJECT_IMAGE3D).count(*format))
       throw error(CL_IMAGE_FORMAT_NOT_SUPPORTED);
 
-   ret_error(errcode_ret, CL_SUCCESS);
+   ret_error(r_errcode, CL_SUCCESS);
    return new image3d(ctx, flags, format, width, height, depth,
                       row_pitch, slice_pitch, host_ptr);
 
 } catch (error &e) {
-   ret_error(errcode_ret, e);
+   ret_error(r_errcode, e);
    return NULL;
 }
 
-PUBLIC cl_int
+CLOVER_API cl_int
 clGetSupportedImageFormats(cl_context d_ctx, cl_mem_flags flags,
                            cl_mem_object_type type, cl_uint count,
-                           cl_image_format *buf, cl_uint *count_ret) try {
+                           cl_image_format *r_buf, cl_uint *r_count) try {
    auto &ctx = obj(d_ctx);
+   auto formats = supported_formats(ctx, type);
 
-   if (flags & ~(CL_MEM_READ_WRITE | CL_MEM_WRITE_ONLY | CL_MEM_READ_ONLY |
-                 CL_MEM_USE_HOST_PTR | CL_MEM_ALLOC_HOST_PTR |
-                 CL_MEM_COPY_HOST_PTR))
-      throw error(CL_INVALID_VALUE);
+   validate_flags(flags, all_mem_flags);
 
-   if (!count && buf)
+   if (r_buf && !r_count)
       throw error(CL_INVALID_VALUE);
 
-   auto formats = supported_formats(ctx, type);
+   if (r_buf)
+      std::copy_n(formats.begin(),
+                  std::min((cl_uint)formats.size(), count),
+                  r_buf);
 
-   if (buf)
-      std::copy_n(formats.begin(), std::min((cl_uint)formats.size(), count),
-                  buf);
-   if (count_ret)
-      *count_ret = formats.size();
+   if (r_count)
+      *r_count = formats.size();
 
    return CL_SUCCESS;
 
@@ -187,29 +215,27 @@ clGetSupportedImageFormats(cl_context d_ctx, cl_mem_flags flags,
    return e.get();
 }
 
-PUBLIC cl_int
-clGetMemObjectInfo(cl_mem obj, cl_mem_info param,
+CLOVER_API cl_int
+clGetMemObjectInfo(cl_mem d_mem, cl_mem_info param,
                    size_t size, void *r_buf, size_t *r_size) try {
    property_buffer buf { r_buf, size, r_size };
-
-   if (!obj)
-      return CL_INVALID_MEM_OBJECT;
+   auto &mem = obj(d_mem);
 
    switch (param) {
    case CL_MEM_TYPE:
-      buf.as_scalar<cl_mem_object_type>() = obj->type();
+      buf.as_scalar<cl_mem_object_type>() = mem.type();
       break;
 
    case CL_MEM_FLAGS:
-      buf.as_scalar<cl_mem_flags>() = obj->flags();
+      buf.as_scalar<cl_mem_flags>() = mem.flags();
       break;
 
    case CL_MEM_SIZE:
-      buf.as_scalar<size_t>() = obj->size();
+      buf.as_scalar<size_t>() = mem.size();
       break;
 
    case CL_MEM_HOST_PTR:
-      buf.as_scalar<void *>() = obj->host_ptr();
+      buf.as_scalar<void *>() = mem.host_ptr();
       break;
 
    case CL_MEM_MAP_COUNT:
@@ -217,20 +243,20 @@ clGetMemObjectInfo(cl_mem obj, cl_mem_info param,
       break;
 
    case CL_MEM_REFERENCE_COUNT:
-      buf.as_scalar<cl_uint>() = obj->ref_count();
+      buf.as_scalar<cl_uint>() = mem.ref_count();
       break;
 
    case CL_MEM_CONTEXT:
-      buf.as_scalar<cl_context>() = &obj->ctx;
+      buf.as_scalar<cl_context>() = desc(mem.context());
       break;
 
    case CL_MEM_ASSOCIATED_MEMOBJECT: {
-      sub_buffer *sub = dynamic_cast<sub_buffer *>(obj);
-      buf.as_scalar<cl_mem>() = (sub ? &sub->parent : NULL);
+      sub_buffer *sub = dynamic_cast<sub_buffer *>(&mem);
+      buf.as_scalar<cl_mem>() = (sub ? desc(sub->parent()) : NULL);
       break;
    }
    case CL_MEM_OFFSET: {
-      sub_buffer *sub = dynamic_cast<sub_buffer *>(obj);
+      sub_buffer *sub = dynamic_cast<sub_buffer *>(&mem);
       buf.as_scalar<size_t>() = (sub ? sub->offset() : 0);
       break;
    }
@@ -244,18 +270,15 @@ clGetMemObjectInfo(cl_mem obj, cl_mem_info param,
    return e.get();
 }
 
-PUBLIC cl_int
-clGetImageInfo(cl_mem obj, cl_image_info param,
+CLOVER_API cl_int
+clGetImageInfo(cl_mem d_mem, cl_image_info param,
                size_t size, void *r_buf, size_t *r_size) try {
    property_buffer buf { r_buf, size, r_size };
-   image *img = dynamic_cast<image *>(obj);
-
-   if (!img)
-      return CL_INVALID_MEM_OBJECT;
+   auto &img = obj<image>(d_mem);
 
    switch (param) {
    case CL_IMAGE_FORMAT:
-      buf.as_scalar<cl_image_format>() = img->format();
+      buf.as_scalar<cl_image_format>() = img.format();
       break;
 
    case CL_IMAGE_ELEMENT_SIZE:
@@ -263,23 +286,23 @@ clGetImageInfo(cl_mem obj, cl_image_info param,
       break;
 
    case CL_IMAGE_ROW_PITCH:
-      buf.as_scalar<size_t>() = img->row_pitch();
+      buf.as_scalar<size_t>() = img.row_pitch();
       break;
 
    case CL_IMAGE_SLICE_PITCH:
-      buf.as_scalar<size_t>() = img->slice_pitch();
+      buf.as_scalar<size_t>() = img.slice_pitch();
       break;
 
    case CL_IMAGE_WIDTH:
-      buf.as_scalar<size_t>() = img->width();
+      buf.as_scalar<size_t>() = img.width();
       break;
 
    case CL_IMAGE_HEIGHT:
-      buf.as_scalar<size_t>() = img->height();
+      buf.as_scalar<size_t>() = img.height();
       break;
 
    case CL_IMAGE_DEPTH:
-      buf.as_scalar<size_t>() = img->depth();
+      buf.as_scalar<size_t>() = img.depth();
       break;
 
    default:
@@ -292,37 +315,51 @@ clGetImageInfo(cl_mem obj, cl_image_info param,
    return e.get();
 }
 
-PUBLIC cl_int
-clRetainMemObject(cl_mem obj) {
-   if (!obj)
-      return CL_INVALID_MEM_OBJECT;
-
-   obj->retain();
+CLOVER_API cl_int
+clRetainMemObject(cl_mem d_mem) try {
+   obj(d_mem).retain();
    return CL_SUCCESS;
-}
 
-PUBLIC cl_int
-clReleaseMemObject(cl_mem obj) {
-   if (!obj)
-      return CL_INVALID_MEM_OBJECT;
+} catch (error &e) {
+   return e.get();
+}
 
-   if (obj->release())
-      delete obj;
+CLOVER_API cl_int
+clReleaseMemObject(cl_mem d_mem) try {
+   if (obj(d_mem).release())
+      delete pobj(d_mem);
 
    return CL_SUCCESS;
+
+} catch (error &e) {
+   return e.get();
 }
 
-PUBLIC cl_int
-clSetMemObjectDestructorCallback(cl_mem obj,
+CLOVER_API cl_int
+clSetMemObjectDestructorCallback(cl_mem d_mem,
                                  void (CL_CALLBACK *pfn_notify)(cl_mem, void *),
-                                 void *user_data) {
-   if (!obj)
-      return CL_INVALID_MEM_OBJECT;
+                                 void *user_data) try {
+   auto &mem = obj(d_mem);
 
    if (!pfn_notify)
       return CL_INVALID_VALUE;
 
-   obj->destroy_notify([=]{ pfn_notify(obj, user_data); });
+   mem.destroy_notify([=]{ pfn_notify(d_mem, user_data); });
 
    return CL_SUCCESS;
+
+} catch (error &e) {
+   return e.get();
+}
+
+CLOVER_API cl_mem
+clCreateImage(cl_context d_ctx, cl_mem_flags flags,
+              const cl_image_format *format,
+              const cl_image_desc *image_desc,
+              void *host_ptr, cl_int *r_errcode) {
+   // This function was added in OpenCL 1.2
+   std::cerr << "CL user error: clCreateImage() not supported by OpenCL 1.1." <<
+                std::endl;
+   ret_error(r_errcode, CL_INVALID_OPERATION);
+   return NULL;
 }