st/nine: Add debug warning when application uses sw processing
[mesa.git] / src / gallium / state_trackers / clover / api / memory.cpp
index b57ce1d388c613f36e5eb510b634b77f6dfe6df6..3ff6ba0e1c505342f773a419a5aac3f3eceb7ad3 100644 (file)
 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
-// THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
-// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-// SOFTWARE.
+// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// 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(*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 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 {
-   if (!ctx)
-      throw error(CL_INVALID_CONTEXT);
+                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);
@@ -116,28 +143,29 @@ clCreateImage2D(cl_context 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);
-   return new image2d(*ctx, flags, format, width, height,
+   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 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 {
-   if (!ctx)
-      throw error(CL_INVALID_CONTEXT);
+                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);
@@ -152,37 +180,34 @@ clCreateImage3D(cl_context 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);
-   return new image3d(*ctx, flags, format, width, height, depth,
+   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
-clGetSupportedImageFormats(cl_context ctx, cl_mem_flags flags,
+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 {
-   if (!ctx)
-      throw error(CL_INVALID_CONTEXT);
+                           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;
 
@@ -190,116 +215,151 @@ clGetSupportedImageFormats(cl_context ctx, cl_mem_flags flags,
    return e.get();
 }
 
-PUBLIC cl_int
-clGetMemObjectInfo(cl_mem obj, cl_mem_info param,
-                   size_t size, void *buf, size_t *size_ret) {
-   if (!obj)
-      return CL_INVALID_MEM_OBJECT;
+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 };
+   auto &mem = obj(d_mem);
 
    switch (param) {
    case CL_MEM_TYPE:
-      return scalar_property<cl_mem_object_type>(buf, size, size_ret,
-                                                 obj->type());
+      buf.as_scalar<cl_mem_object_type>() = mem.type();
+      break;
 
    case CL_MEM_FLAGS:
-      return scalar_property<cl_mem_flags>(buf, size, size_ret, obj->flags());
+      buf.as_scalar<cl_mem_flags>() = mem.flags();
+      break;
 
    case CL_MEM_SIZE:
-      return scalar_property<size_t>(buf, size, size_ret, obj->size());
+      buf.as_scalar<size_t>() = mem.size();
+      break;
 
    case CL_MEM_HOST_PTR:
-      return scalar_property<void *>(buf, size, size_ret, obj->host_ptr());
+      buf.as_scalar<void *>() = mem.host_ptr();
+      break;
 
    case CL_MEM_MAP_COUNT:
-      return scalar_property<cl_uint>(buf, size, size_ret, 0);
+      buf.as_scalar<cl_uint>() = 0;
+      break;
 
    case CL_MEM_REFERENCE_COUNT:
-      return scalar_property<cl_uint>(buf, size, size_ret, obj->ref_count());
+      buf.as_scalar<cl_uint>() = mem.ref_count();
+      break;
 
    case CL_MEM_CONTEXT:
-      return scalar_property<cl_context>(buf, size, size_ret, &obj->ctx);
+      buf.as_scalar<cl_context>() = desc(mem.context());
+      break;
 
    case CL_MEM_ASSOCIATED_MEMOBJECT: {
-      sub_buffer *sub = dynamic_cast<sub_buffer *>(obj);
-      return scalar_property<cl_mem>(buf, size, size_ret,
-                                     (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);
-      return scalar_property<size_t>(buf, size, size_ret,
-                                     (sub ? sub->offset() : 0));
+      sub_buffer *sub = dynamic_cast<sub_buffer *>(&mem);
+      buf.as_scalar<size_t>() = (sub ? sub->offset() : 0);
+      break;
    }
    default:
-      return CL_INVALID_VALUE;
+      throw error(CL_INVALID_VALUE);
    }
+
+   return CL_SUCCESS;
+
+} catch (error &e) {
+   return e.get();
 }
 
-PUBLIC cl_int
-clGetImageInfo(cl_mem obj, cl_image_info param,
-               size_t size, void *buf, size_t *size_ret) {
-   image *img = dynamic_cast<image *>(obj);
-   if (!img)
-      return CL_INVALID_MEM_OBJECT;
+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 };
+   auto &img = obj<image>(d_mem);
 
    switch (param) {
    case CL_IMAGE_FORMAT:
-      return scalar_property<cl_image_format>(buf, size, size_ret,
-                                              img->format());
+      buf.as_scalar<cl_image_format>() = img.format();
+      break;
 
    case CL_IMAGE_ELEMENT_SIZE:
-      return scalar_property<size_t>(buf, size, size_ret, 0);
+      buf.as_scalar<size_t>() = 0;
+      break;
 
    case CL_IMAGE_ROW_PITCH:
-      return scalar_property<size_t>(buf, size, size_ret, img->row_pitch());
+      buf.as_scalar<size_t>() = img.row_pitch();
+      break;
 
    case CL_IMAGE_SLICE_PITCH:
-      return scalar_property<size_t>(buf, size, size_ret, img->slice_pitch());
+      buf.as_scalar<size_t>() = img.slice_pitch();
+      break;
 
    case CL_IMAGE_WIDTH:
-      return scalar_property<size_t>(buf, size, size_ret, img->width());
+      buf.as_scalar<size_t>() = img.width();
+      break;
 
    case CL_IMAGE_HEIGHT:
-      return scalar_property<size_t>(buf, size, size_ret, img->height());
+      buf.as_scalar<size_t>() = img.height();
+      break;
 
    case CL_IMAGE_DEPTH:
-      return scalar_property<size_t>(buf, size, size_ret, img->depth());
+      buf.as_scalar<size_t>() = img.depth();
+      break;
 
    default:
-      return CL_INVALID_VALUE;
+      throw error(CL_INVALID_VALUE);
    }
-}
-
-PUBLIC cl_int
-clRetainMemObject(cl_mem obj) {
-   if (!obj)
-      return CL_INVALID_MEM_OBJECT;
 
-   obj->retain();
    return CL_SUCCESS;
+
+} catch (error &e) {
+   return e.get();
 }
 
-PUBLIC cl_int
-clReleaseMemObject(cl_mem obj) {
-   if (!obj)
-      return CL_INVALID_MEM_OBJECT;
+CLOVER_API cl_int
+clRetainMemObject(cl_mem d_mem) try {
+   obj(d_mem).retain();
+   return CL_SUCCESS;
+
+} 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;
 }