1 // 2 // Copyright 2012 Francisco Jerez 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a 5 // copy of this software and associated documentation files (the "Software"), 6 // to deal in the Software without restriction, including without limitation 7 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 // and/or sell copies of the Software, and to permit persons to whom the 9 // Software is furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 // OTHER DEALINGS IN THE SOFTWARE. 21 // 22 23 #include "core/resource.hpp" 24 #include "core/memory.hpp" 25 #include "pipe/p_screen.h" 26 #include "util/u_sampler.h" 27 #include "util/u_format.h" 28 #include "util/u_inlines.h" 29 30 using namespace clover; 31 32 namespace { 33 class box { 34 public: 35 box(const resource::vector &origin, const resource::vector &size) : 36 pipe({ (int)origin[0], (int)origin[1], 37 (int)origin[2], (int)size[0], 38 (int)size[1], (int)size[2] }) { 39 } 40 41 operator const pipe_box *() { 42 return &pipe; 43 } 44 45 protected: 46 pipe_box pipe; 47 }; 48 } 49 50 resource::resource(clover::device &dev, memory_obj &obj) : 51 device(dev), obj(obj), pipe(NULL), offset() { 52 } 53 54 resource::~resource() { 55 } 56 57 void 58 resource::copy(command_queue &q, const vector &origin, const vector ®ion, 59 resource &src_res, const vector &src_origin) { 60 auto p = offset + origin; 61 62 q.pipe->resource_copy_region(q.pipe, pipe, 0, p[0], p[1], p[2], 63 src_res.pipe, 0, 64 box(src_res.offset + src_origin, region)); 65 } 66 67 void * 68 resource::add_map(command_queue &q, cl_map_flags flags, bool blocking, 69 const vector &origin, const vector ®ion) { 70 maps.emplace_back(q, *this, flags, blocking, origin, region); 71 return maps.back(); 72 } 73 74 void 75 resource::del_map(void *p) { 76 erase_if([&](const mapping &m) { 77 return static_cast<void *>(m) == p; 78 }, maps); 79 } 80 81 unsigned 82 resource::map_count() const { 83 return maps.size(); 84 } 85 86 pipe_sampler_view * 87 resource::bind_sampler_view(command_queue &q) { 88 pipe_sampler_view info; 89 90 u_sampler_view_default_template(&info, pipe, pipe->format); 91 return q.pipe->create_sampler_view(q.pipe, pipe, &info); 92 } 93 94 void 95 resource::unbind_sampler_view(command_queue &q, 96 pipe_sampler_view *st) { 97 q.pipe->sampler_view_destroy(q.pipe, st); 98 } 99 100 pipe_surface * 101 resource::bind_surface(command_queue &q, bool rw) { 102 pipe_surface info {}; 103 104 info.format = pipe->format; 105 info.writable = rw; 106 107 if (pipe->target == PIPE_BUFFER) 108 info.u.buf.last_element = pipe->width0 - 1; 109 110 return q.pipe->create_surface(q.pipe, pipe, &info); 111 } 112 113 void 114 resource::unbind_surface(command_queue &q, pipe_surface *st) { 115 q.pipe->surface_destroy(q.pipe, st); 116 } 117 118 root_resource::root_resource(clover::device &dev, memory_obj &obj, 119 command_queue &q, const std::string &data) : 120 resource(dev, obj) { 121 pipe_resource info {}; 122 const bool user_ptr_support = dev.pipe->get_param(dev.pipe, 123 PIPE_CAP_RESOURCE_FROM_USER_MEMORY); 124 125 if (image *img = dynamic_cast<image *>(&obj)) { 126 info.format = translate_format(img->format()); 127 info.width0 = img->width(); 128 info.height0 = img->height(); 129 info.depth0 = img->depth(); 130 } else { 131 info.width0 = obj.size(); 132 info.height0 = 1; 133 info.depth0 = 1; 134 } 135 136 info.array_size = 1; 137 info.target = translate_target(obj.type()); 138 info.bind = (PIPE_BIND_SAMPLER_VIEW | 139 PIPE_BIND_COMPUTE_RESOURCE | 140 PIPE_BIND_GLOBAL); 141 142 if (obj.flags() & CL_MEM_USE_HOST_PTR && user_ptr_support) { 143 // Page alignment is normally required for this, just try, hope for the 144 // best and fall back if it fails. 145 pipe = dev.pipe->resource_from_user_memory(dev.pipe, &info, obj.host_ptr()); 146 if (pipe) 147 return; 148 } 149 150 if (obj.flags() & (CL_MEM_ALLOC_HOST_PTR | CL_MEM_USE_HOST_PTR)) { 151 info.usage = PIPE_USAGE_STAGING; 152 } 153 154 pipe = dev.pipe->resource_create(dev.pipe, &info); 155 if (!pipe) 156 throw error(CL_OUT_OF_RESOURCES); 157 158 if (obj.flags() & (CL_MEM_USE_HOST_PTR | CL_MEM_COPY_HOST_PTR)) { 159 const void *data_ptr = !data.empty() ? data.data() : obj.host_ptr(); 160 box rect { {{ 0, 0, 0 }}, {{ info.width0, info.height0, info.depth0 }} }; 161 unsigned cpp = util_format_get_blocksize(info.format); 162 163 if (pipe->target == PIPE_BUFFER) 164 q.pipe->buffer_subdata(q.pipe, pipe, PIPE_TRANSFER_WRITE, 165 0, info.width0, data_ptr); 166 else 167 q.pipe->texture_subdata(q.pipe, pipe, 0, PIPE_TRANSFER_WRITE, 168 rect, data_ptr, cpp * info.width0, 169 cpp * info.width0 * info.height0); 170 } 171 } 172 173 root_resource::root_resource(clover::device &dev, memory_obj &obj, 174 root_resource &r) : 175 resource(dev, obj) { 176 assert(0); // XXX -- resource shared among dev and r.dev 177 } 178 179 root_resource::~root_resource() { 180 pipe_resource_reference(&this->pipe, NULL); 181 } 182 183 sub_resource::sub_resource(resource &r, const vector &offset) : 184 resource(r.device(), r.obj) { 185 this->pipe = r.pipe; 186 this->offset = r.offset + offset; 187 } 188 189 mapping::mapping(command_queue &q, resource &r, 190 cl_map_flags flags, bool blocking, 191 const resource::vector &origin, 192 const resource::vector ®ion) : 193 pctx(q.pipe), pres(NULL) { 194 unsigned usage = ((flags & CL_MAP_WRITE ? PIPE_TRANSFER_WRITE : 0 ) | 195 (flags & CL_MAP_READ ? PIPE_TRANSFER_READ : 0 ) | 196 (flags & CL_MAP_WRITE_INVALIDATE_REGION ? 197 PIPE_TRANSFER_DISCARD_RANGE : 0) | 198 (!blocking ? PIPE_TRANSFER_UNSYNCHRONIZED : 0)); 199 200 p = pctx->transfer_map(pctx, r.pipe, 0, usage, 201 box(origin + r.offset, region), &pxfer); 202 if (!p) { 203 pxfer = NULL; 204 throw error(CL_OUT_OF_RESOURCES); 205 } 206 pipe_resource_reference(&pres, r.pipe); 207 } 208 209 mapping::mapping(mapping &&m) : 210 pctx(m.pctx), pxfer(m.pxfer), pres(m.pres), p(m.p) { 211 m.pctx = NULL; 212 m.pxfer = NULL; 213 m.pres = NULL; 214 m.p = NULL; 215 } 216 217 mapping::~mapping() { 218 if (pxfer) { 219 pctx->transfer_unmap(pctx, pxfer); 220 } 221 pipe_resource_reference(&pres, NULL); 222 } 223 224 mapping & 225 mapping::operator=(mapping m) { 226 std::swap(pctx, m.pctx); 227 std::swap(pxfer, m.pxfer); 228 std::swap(pres, m.pres); 229 std::swap(p, m.p); 230 return *this; 231 } 232