Path: blob/21.2-virgl/src/gallium/frontends/clover/api/memory.cpp
4572 views
//1// Copyright 2012 Francisco Jerez2//3// Permission is hereby granted, free of charge, to any person obtaining a4// copy of this software and associated documentation files (the "Software"),5// to deal in the Software without restriction, including without limitation6// the rights to use, copy, modify, merge, publish, distribute, sublicense,7// and/or sell copies of the Software, and to permit persons to whom the8// Software is furnished to do so, subject to the following conditions:9//10// The above copyright notice and this permission notice shall be included in11// all copies or substantial portions of the Software.12//13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL16// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR17// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,18// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR19// OTHER DEALINGS IN THE SOFTWARE.20//2122#include "util/format/u_format.h"23#include "util/u_math.h"24#include "api/util.hpp"25#include "core/memory.hpp"26#include "core/format.hpp"2728using namespace clover;2930namespace {31cl_mem_flags32validate_flags(cl_mem d_parent, cl_mem_flags d_flags, bool svm) {33const cl_mem_flags dev_access_flags =34CL_MEM_READ_WRITE | CL_MEM_WRITE_ONLY | CL_MEM_READ_ONLY;35const cl_mem_flags host_ptr_flags =36CL_MEM_USE_HOST_PTR | CL_MEM_ALLOC_HOST_PTR | CL_MEM_COPY_HOST_PTR;37const cl_mem_flags host_access_flags =38CL_MEM_HOST_WRITE_ONLY | CL_MEM_HOST_READ_ONLY | CL_MEM_HOST_NO_ACCESS;39const cl_mem_flags svm_flags =40CL_MEM_SVM_FINE_GRAIN_BUFFER | CL_MEM_SVM_ATOMICS;4142const cl_mem_flags valid_flags =43dev_access_flags44| (svm || d_parent ? 0 : host_ptr_flags)45| (svm ? svm_flags : host_access_flags);4647if ((d_flags & ~valid_flags) ||48util_bitcount(d_flags & dev_access_flags) > 1 ||49util_bitcount(d_flags & host_access_flags) > 1)50throw error(CL_INVALID_VALUE);5152if ((d_flags & CL_MEM_USE_HOST_PTR) &&53(d_flags & (CL_MEM_COPY_HOST_PTR | CL_MEM_ALLOC_HOST_PTR)))54throw error(CL_INVALID_VALUE);5556if ((d_flags & CL_MEM_SVM_ATOMICS) &&57!(d_flags & CL_MEM_SVM_FINE_GRAIN_BUFFER))58throw error(CL_INVALID_VALUE);5960if (d_parent) {61const auto &parent = obj(d_parent);62const cl_mem_flags flags = (d_flags |63(d_flags & dev_access_flags ? 0 :64parent.flags() & dev_access_flags) |65(d_flags & host_access_flags ? 0 :66parent.flags() & host_access_flags) |67(parent.flags() & host_ptr_flags));6869if (~flags & parent.flags() & (dev_access_flags & ~CL_MEM_READ_WRITE))70throw error(CL_INVALID_VALUE);7172// Check if new host access flags cause a mismatch between73// host-read/write-only.74if (!(flags & CL_MEM_HOST_NO_ACCESS) &&75(~flags & parent.flags() & host_access_flags))76throw error(CL_INVALID_VALUE);7778return flags;7980} else {81return d_flags | (d_flags & dev_access_flags ? 0 : CL_MEM_READ_WRITE);82}83}8485std::vector<cl_mem_properties>86fill_properties(const cl_mem_properties *d_properties) {87std::vector<cl_mem_properties> properties;88if (d_properties) {89while (*d_properties) {90if (*d_properties != 0)91throw error(CL_INVALID_PROPERTY);9293properties.push_back(*d_properties);94d_properties++;95};96properties.push_back(0);97}98return properties;99}100}101102CLOVER_API cl_mem103clCreateBufferWithProperties(cl_context d_ctx,104const cl_mem_properties *d_properties,105cl_mem_flags d_flags, size_t size,106void *host_ptr, cl_int *r_errcode) try {107108auto &ctx = obj(d_ctx);109const cl_mem_flags flags = validate_flags(NULL, d_flags, false);110std::vector<cl_mem_properties> properties = fill_properties(d_properties);111112if (bool(host_ptr) != bool(flags & (CL_MEM_USE_HOST_PTR |113CL_MEM_COPY_HOST_PTR)))114throw error(CL_INVALID_HOST_PTR);115116if (!size ||117size > fold(maximum(), cl_ulong(0),118map(std::mem_fn(&device::max_mem_alloc_size), ctx.devices())119))120throw error(CL_INVALID_BUFFER_SIZE);121122ret_error(r_errcode, CL_SUCCESS);123return new root_buffer(ctx, properties, flags, size, host_ptr);124} catch (error &e) {125ret_error(r_errcode, e);126return NULL;127}128129130CLOVER_API cl_mem131clCreateBuffer(cl_context d_ctx, cl_mem_flags d_flags, size_t size,132void *host_ptr, cl_int *r_errcode) {133return clCreateBufferWithProperties(d_ctx, NULL, d_flags, size,134host_ptr, r_errcode);135}136137CLOVER_API cl_mem138clCreateSubBuffer(cl_mem d_mem, cl_mem_flags d_flags,139cl_buffer_create_type op,140const void *op_info, cl_int *r_errcode) try {141auto &parent = obj<root_buffer>(d_mem);142const cl_mem_flags flags = validate_flags(d_mem, d_flags, false);143144if (op == CL_BUFFER_CREATE_TYPE_REGION) {145auto reg = reinterpret_cast<const cl_buffer_region *>(op_info);146147if (!reg ||148reg->origin > parent.size() ||149reg->origin + reg->size > parent.size())150throw error(CL_INVALID_VALUE);151152if (!reg->size)153throw error(CL_INVALID_BUFFER_SIZE);154155ret_error(r_errcode, CL_SUCCESS);156return new sub_buffer(parent, flags, reg->origin, reg->size);157158} else {159throw error(CL_INVALID_VALUE);160}161162} catch (error &e) {163ret_error(r_errcode, e);164return NULL;165}166167CLOVER_API cl_mem168clCreateImageWithProperties(cl_context d_ctx,169const cl_mem_properties *d_properties,170cl_mem_flags d_flags,171const cl_image_format *format,172const cl_image_desc *desc,173void *host_ptr, cl_int *r_errcode) try {174auto &ctx = obj(d_ctx);175176if (!any_of(std::mem_fn(&device::image_support), ctx.devices()))177throw error(CL_INVALID_OPERATION);178179if (!format)180throw error(CL_INVALID_IMAGE_FORMAT_DESCRIPTOR);181182if (!desc)183throw error(CL_INVALID_IMAGE_DESCRIPTOR);184185if (desc->image_array_size == 0 &&186(desc->image_type == CL_MEM_OBJECT_IMAGE1D_ARRAY ||187desc->image_type == CL_MEM_OBJECT_IMAGE2D_ARRAY))188throw error(CL_INVALID_IMAGE_DESCRIPTOR);189190if (!host_ptr &&191(desc->image_row_pitch || desc->image_slice_pitch))192throw error(CL_INVALID_IMAGE_DESCRIPTOR);193194if (desc->num_mip_levels || desc->num_samples)195throw error(CL_INVALID_IMAGE_DESCRIPTOR);196197if (bool(desc->buffer) != (desc->image_type == CL_MEM_OBJECT_IMAGE1D_BUFFER))198throw error(CL_INVALID_IMAGE_DESCRIPTOR);199200if (bool(host_ptr) != bool(d_flags & (CL_MEM_USE_HOST_PTR |201CL_MEM_COPY_HOST_PTR)))202throw error(CL_INVALID_HOST_PTR);203204const cl_mem_flags flags = validate_flags(desc->buffer, d_flags, false);205206if (!supported_formats(ctx, desc->image_type).count(*format))207throw error(CL_IMAGE_FORMAT_NOT_SUPPORTED);208209std::vector<cl_mem_properties> properties = fill_properties(d_properties);210ret_error(r_errcode, CL_SUCCESS);211212const size_t row_pitch = desc->image_row_pitch ? desc->image_row_pitch :213util_format_get_blocksize(translate_format(*format)) * desc->image_width;214215switch (desc->image_type) {216case CL_MEM_OBJECT_IMAGE1D:217if (!desc->image_width)218throw error(CL_INVALID_IMAGE_SIZE);219220if (all_of([=](const device &dev) {221const size_t max = dev.max_image_size();222return (desc->image_width > max);223}, ctx.devices()))224throw error(CL_INVALID_IMAGE_SIZE);225226return new image1d(ctx, properties, flags, format,227desc->image_width,228row_pitch, host_ptr);229230case CL_MEM_OBJECT_IMAGE2D:231if (!desc->image_width || !desc->image_height)232throw error(CL_INVALID_IMAGE_SIZE);233234if (all_of([=](const device &dev) {235const size_t max = dev.max_image_size();236return (desc->image_width > max ||237desc->image_height > max);238}, ctx.devices()))239throw error(CL_INVALID_IMAGE_SIZE);240241return new image2d(ctx, properties, flags, format,242desc->image_width, desc->image_height,243row_pitch, host_ptr);244245case CL_MEM_OBJECT_IMAGE3D: {246if (!desc->image_width || !desc->image_height || !desc->image_depth)247throw error(CL_INVALID_IMAGE_SIZE);248249if (all_of([=](const device &dev) {250const size_t max = dev.max_image_size_3d();251return (desc->image_width > max ||252desc->image_height > max ||253desc->image_depth > max);254}, ctx.devices()))255throw error(CL_INVALID_IMAGE_SIZE);256257const size_t slice_pitch = desc->image_slice_pitch ?258desc->image_slice_pitch : row_pitch * desc->image_height;259260return new image3d(ctx, properties, flags, format,261desc->image_width, desc->image_height,262desc->image_depth, row_pitch,263slice_pitch, host_ptr);264}265266case CL_MEM_OBJECT_IMAGE1D_ARRAY:267case CL_MEM_OBJECT_IMAGE1D_BUFFER:268case CL_MEM_OBJECT_IMAGE2D_ARRAY:269// XXX - Not implemented.270throw error(CL_IMAGE_FORMAT_NOT_SUPPORTED);271272default:273throw error(CL_INVALID_IMAGE_DESCRIPTOR);274}275276} catch (error &e) {277ret_error(r_errcode, e);278return NULL;279}280281CLOVER_API cl_mem282clCreateImage(cl_context d_ctx,283cl_mem_flags d_flags,284const cl_image_format *format,285const cl_image_desc *desc,286void *host_ptr, cl_int *r_errcode) {287return clCreateImageWithProperties(d_ctx, NULL, d_flags, format, desc, host_ptr, r_errcode);288}289290291CLOVER_API cl_mem292clCreateImage2D(cl_context d_ctx, cl_mem_flags d_flags,293const cl_image_format *format,294size_t width, size_t height, size_t row_pitch,295void *host_ptr, cl_int *r_errcode) {296const cl_image_desc desc = { CL_MEM_OBJECT_IMAGE2D, width, height, 0, 0,297row_pitch, 0, 0, 0, NULL };298299return clCreateImageWithProperties(d_ctx, NULL, d_flags, format, &desc, host_ptr, r_errcode);300}301302CLOVER_API cl_mem303clCreateImage3D(cl_context d_ctx, cl_mem_flags d_flags,304const cl_image_format *format,305size_t width, size_t height, size_t depth,306size_t row_pitch, size_t slice_pitch,307void *host_ptr, cl_int *r_errcode) {308const cl_image_desc desc = { CL_MEM_OBJECT_IMAGE3D, width, height, depth, 0,309row_pitch, slice_pitch, 0, 0, NULL };310311return clCreateImageWithProperties(d_ctx, NULL, d_flags, format, &desc, host_ptr, r_errcode);312}313314CLOVER_API cl_int315clGetSupportedImageFormats(cl_context d_ctx, cl_mem_flags flags,316cl_mem_object_type type, cl_uint count,317cl_image_format *r_buf, cl_uint *r_count) try {318auto &ctx = obj(d_ctx);319auto formats = supported_formats(ctx, type);320321if (flags & CL_MEM_KERNEL_READ_AND_WRITE) {322if (r_count)323*r_count = 0;324return CL_SUCCESS;325}326327if (flags & (CL_MEM_WRITE_ONLY | CL_MEM_READ_WRITE) &&328type == CL_MEM_OBJECT_IMAGE3D) {329if (r_count)330*r_count = 0;331return CL_SUCCESS;332}333334validate_flags(NULL, flags, false);335336if (r_buf && !count)337throw error(CL_INVALID_VALUE);338339if (r_buf)340std::copy_n(formats.begin(),341std::min((cl_uint)formats.size(), count),342r_buf);343344if (r_count)345*r_count = formats.size();346347return CL_SUCCESS;348349} catch (error &e) {350return e.get();351}352353CLOVER_API cl_int354clGetMemObjectInfo(cl_mem d_mem, cl_mem_info param,355size_t size, void *r_buf, size_t *r_size) try {356property_buffer buf { r_buf, size, r_size };357auto &mem = obj(d_mem);358359switch (param) {360case CL_MEM_TYPE:361buf.as_scalar<cl_mem_object_type>() = mem.type();362break;363364case CL_MEM_FLAGS:365buf.as_scalar<cl_mem_flags>() = mem.flags();366break;367368case CL_MEM_SIZE:369buf.as_scalar<size_t>() = mem.size();370break;371372case CL_MEM_HOST_PTR:373buf.as_scalar<void *>() = mem.host_ptr();374break;375376case CL_MEM_MAP_COUNT:377buf.as_scalar<cl_uint>() = 0;378break;379380case CL_MEM_REFERENCE_COUNT:381buf.as_scalar<cl_uint>() = mem.ref_count();382break;383384case CL_MEM_CONTEXT:385buf.as_scalar<cl_context>() = desc(mem.context());386break;387388case CL_MEM_ASSOCIATED_MEMOBJECT: {389sub_buffer *sub = dynamic_cast<sub_buffer *>(&mem);390buf.as_scalar<cl_mem>() = (sub ? desc(sub->parent()) : NULL);391break;392}393case CL_MEM_OFFSET: {394sub_buffer *sub = dynamic_cast<sub_buffer *>(&mem);395buf.as_scalar<size_t>() = (sub ? sub->offset() : 0);396break;397}398case CL_MEM_USES_SVM_POINTER:399case CL_MEM_USES_SVM_POINTER_ARM: {400// with system SVM all host ptrs are SVM pointers401// TODO: once we support devices with lower levels of SVM, we have to402// check the ptr in more detail403const bool system_svm = all_of(std::mem_fn(&device::has_system_svm),404mem.context().devices());405buf.as_scalar<cl_bool>() = mem.host_ptr() && system_svm;406break;407}408case CL_MEM_PROPERTIES:409buf.as_vector<cl_mem_properties>() = mem.properties();410break;411default:412throw error(CL_INVALID_VALUE);413}414415return CL_SUCCESS;416417} catch (error &e) {418return e.get();419}420421CLOVER_API cl_int422clGetImageInfo(cl_mem d_mem, cl_image_info param,423size_t size, void *r_buf, size_t *r_size) try {424property_buffer buf { r_buf, size, r_size };425auto &img = obj<image>(d_mem);426427switch (param) {428case CL_IMAGE_FORMAT:429buf.as_scalar<cl_image_format>() = img.format();430break;431432case CL_IMAGE_ELEMENT_SIZE:433buf.as_scalar<size_t>() = img.pixel_size();434break;435436case CL_IMAGE_ROW_PITCH:437buf.as_scalar<size_t>() = img.row_pitch();438break;439440case CL_IMAGE_SLICE_PITCH:441buf.as_scalar<size_t>() = img.slice_pitch();442break;443444case CL_IMAGE_WIDTH:445buf.as_scalar<size_t>() = img.width();446break;447448case CL_IMAGE_HEIGHT:449buf.as_scalar<size_t>() = img.height();450break;451452case CL_IMAGE_DEPTH:453buf.as_scalar<size_t>() = img.depth();454break;455456case CL_IMAGE_NUM_MIP_LEVELS:457buf.as_scalar<cl_uint>() = 0;458break;459460case CL_IMAGE_NUM_SAMPLES:461buf.as_scalar<cl_uint>() = 0;462break;463464default:465throw error(CL_INVALID_VALUE);466}467468return CL_SUCCESS;469470} catch (error &e) {471return e.get();472}473474CLOVER_API cl_int475clRetainMemObject(cl_mem d_mem) try {476obj(d_mem).retain();477return CL_SUCCESS;478479} catch (error &e) {480return e.get();481}482483CLOVER_API cl_int484clReleaseMemObject(cl_mem d_mem) try {485if (obj(d_mem).release())486delete pobj(d_mem);487488return CL_SUCCESS;489490} catch (error &e) {491return e.get();492}493494CLOVER_API cl_int495clSetMemObjectDestructorCallback(cl_mem d_mem,496void (CL_CALLBACK *pfn_notify)(cl_mem, void *),497void *user_data) try {498auto &mem = obj(d_mem);499500if (!pfn_notify)501return CL_INVALID_VALUE;502503mem.destroy_notify([=]{ pfn_notify(d_mem, user_data); });504505return CL_SUCCESS;506507} catch (error &e) {508return e.get();509}510511CLOVER_API void *512clSVMAlloc(cl_context d_ctx,513cl_svm_mem_flags flags,514size_t size,515unsigned int alignment) try {516auto &ctx = obj(d_ctx);517518if (!any_of(std::mem_fn(&device::svm_support), ctx.devices()))519return NULL;520521validate_flags(NULL, flags, true);522523if (!size ||524size > fold(minimum(), cl_ulong(ULONG_MAX),525map(std::mem_fn(&device::max_mem_alloc_size), ctx.devices())))526return nullptr;527528if (!util_is_power_of_two_or_zero(alignment))529return nullptr;530531if (!alignment)532alignment = 0x80; // sizeof(long16)533534#if HAVE_POSIX_MEMALIGN535bool can_emulate = all_of(std::mem_fn(&device::has_system_svm), ctx.devices());536if (can_emulate) {537// we can ignore all the flags as it's not required to honor them.538void *ptr = nullptr;539if (alignment < sizeof(void*))540alignment = sizeof(void*);541posix_memalign(&ptr, alignment, size);542543if (ptr)544ctx.add_svm_allocation(ptr, size);545546return ptr;547}548#endif549550CLOVER_NOT_SUPPORTED_UNTIL("2.0");551return nullptr;552553} catch (error &e) {554return nullptr;555}556557CLOVER_API void558clSVMFree(cl_context d_ctx,559void *svm_pointer) try {560auto &ctx = obj(d_ctx);561562if (!any_of(std::mem_fn(&device::svm_support), ctx.devices()))563return;564565bool can_emulate = all_of(std::mem_fn(&device::has_system_svm), ctx.devices());566567if (can_emulate) {568ctx.remove_svm_allocation(svm_pointer);569return free(svm_pointer);570}571572CLOVER_NOT_SUPPORTED_UNTIL("2.0");573574} catch (error &e) {575}576577578