1 /************************************************************************** 2 * 3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28 /** 29 * @file 30 * A variation of malloc buffers which get transferred to real graphics memory 31 * when there is an attempt to validate them. 32 * 33 * @author Jose Fonseca <jrfonseca (at) tungstengraphics.com> 34 */ 35 36 37 #include "util/u_debug.h" 38 #include "util/u_memory.h" 39 #include "pb_buffer.h" 40 #include "pb_bufmgr.h" 41 42 43 struct pb_ondemand_manager; 44 45 46 struct pb_ondemand_buffer 47 { 48 struct pb_buffer base; 49 50 struct pb_ondemand_manager *mgr; 51 52 /** Regular malloc'ed memory */ 53 void *data; 54 unsigned mapcount; 55 56 /** Real buffer */ 57 struct pb_buffer *buffer; 58 pb_size size; 59 struct pb_desc desc; 60 }; 61 62 63 struct pb_ondemand_manager 64 { 65 struct pb_manager base; 66 67 struct pb_manager *provider; 68 }; 69 70 71 extern const struct pb_vtbl pb_ondemand_buffer_vtbl; 72 73 static INLINE struct pb_ondemand_buffer * 74 pb_ondemand_buffer(struct pb_buffer *buf) 75 { 76 assert(buf); 77 if (!buf) 78 return NULL; 79 assert(buf->vtbl == &pb_ondemand_buffer_vtbl); 80 return (struct pb_ondemand_buffer *)buf; 81 } 82 83 static INLINE struct pb_ondemand_manager * 84 pb_ondemand_manager(struct pb_manager *mgr) 85 { 86 assert(mgr); 87 return (struct pb_ondemand_manager *)mgr; 88 } 89 90 91 static void 92 pb_ondemand_buffer_destroy(struct pb_buffer *_buf) 93 { 94 struct pb_ondemand_buffer *buf = pb_ondemand_buffer(_buf); 95 96 pb_reference(&buf->buffer, NULL); 97 98 align_free(buf->data); 99 100 FREE(buf); 101 } 102 103 104 static void * 105 pb_ondemand_buffer_map(struct pb_buffer *_buf, 106 unsigned flags, void *flush_ctx) 107 { 108 struct pb_ondemand_buffer *buf = pb_ondemand_buffer(_buf); 109 110 if(buf->buffer) { 111 assert(!buf->data); 112 return pb_map(buf->buffer, flags, flush_ctx); 113 } 114 else { 115 assert(buf->data); 116 ++buf->mapcount; 117 return buf->data; 118 } 119 } 120 121 122 static void 123 pb_ondemand_buffer_unmap(struct pb_buffer *_buf) 124 { 125 struct pb_ondemand_buffer *buf = pb_ondemand_buffer(_buf); 126 127 if(buf->buffer) { 128 assert(!buf->data); 129 pb_unmap(buf->buffer); 130 } 131 else { 132 assert(buf->data); 133 assert(buf->mapcount); 134 if(buf->mapcount) 135 --buf->mapcount; 136 } 137 } 138 139 140 static enum pipe_error 141 pb_ondemand_buffer_instantiate(struct pb_ondemand_buffer *buf) 142 { 143 if(!buf->buffer) { 144 struct pb_manager *provider = buf->mgr->provider; 145 uint8_t *map; 146 147 assert(!buf->mapcount); 148 149 buf->buffer = provider->create_buffer(provider, buf->size, &buf->desc); 150 if(!buf->buffer) 151 return PIPE_ERROR_OUT_OF_MEMORY; 152 153 map = pb_map(buf->buffer, PB_USAGE_CPU_READ, NULL); 154 if(!map) { 155 pb_reference(&buf->buffer, NULL); 156 return PIPE_ERROR; 157 } 158 159 memcpy(map, buf->data, buf->size); 160 161 pb_unmap(buf->buffer); 162 163 if(!buf->mapcount) { 164 FREE(buf->data); 165 buf->data = NULL; 166 } 167 } 168 169 return PIPE_OK; 170 } 171 172 static enum pipe_error 173 pb_ondemand_buffer_validate(struct pb_buffer *_buf, 174 struct pb_validate *vl, 175 unsigned flags) 176 { 177 struct pb_ondemand_buffer *buf = pb_ondemand_buffer(_buf); 178 enum pipe_error ret; 179 180 assert(!buf->mapcount); 181 if(buf->mapcount) 182 return PIPE_ERROR; 183 184 ret = pb_ondemand_buffer_instantiate(buf); 185 if(ret != PIPE_OK) 186 return ret; 187 188 return pb_validate(buf->buffer, vl, flags); 189 } 190 191 192 static void 193 pb_ondemand_buffer_fence(struct pb_buffer *_buf, 194 struct pipe_fence_handle *fence) 195 { 196 struct pb_ondemand_buffer *buf = pb_ondemand_buffer(_buf); 197 198 assert(buf->buffer); 199 if(!buf->buffer) 200 return; 201 202 pb_fence(buf->buffer, fence); 203 } 204 205 206 static void 207 pb_ondemand_buffer_get_base_buffer(struct pb_buffer *_buf, 208 struct pb_buffer **base_buf, 209 pb_size *offset) 210 { 211 struct pb_ondemand_buffer *buf = pb_ondemand_buffer(_buf); 212 213 if(pb_ondemand_buffer_instantiate(buf) != PIPE_OK) { 214 assert(0); 215 *base_buf = &buf->base; 216 *offset = 0; 217 return; 218 } 219 220 pb_get_base_buffer(buf->buffer, base_buf, offset); 221 } 222 223 224 const struct pb_vtbl 225 pb_ondemand_buffer_vtbl = { 226 pb_ondemand_buffer_destroy, 227 pb_ondemand_buffer_map, 228 pb_ondemand_buffer_unmap, 229 pb_ondemand_buffer_validate, 230 pb_ondemand_buffer_fence, 231 pb_ondemand_buffer_get_base_buffer 232 }; 233 234 235 static struct pb_buffer * 236 pb_ondemand_manager_create_buffer(struct pb_manager *_mgr, 237 pb_size size, 238 const struct pb_desc *desc) 239 { 240 struct pb_ondemand_manager *mgr = pb_ondemand_manager(_mgr); 241 struct pb_ondemand_buffer *buf; 242 243 buf = CALLOC_STRUCT(pb_ondemand_buffer); 244 if(!buf) 245 return NULL; 246 247 pipe_reference_init(&buf->base.reference, 1); 248 buf->base.alignment = desc->alignment; 249 buf->base.usage = desc->usage; 250 buf->base.size = size; 251 buf->base.vtbl = &pb_ondemand_buffer_vtbl; 252 253 buf->mgr = mgr; 254 255 buf->data = align_malloc(size, desc->alignment < sizeof(void*) ? sizeof(void*) : desc->alignment); 256 if(!buf->data) { 257 FREE(buf); 258 return NULL; 259 } 260 261 buf->size = size; 262 buf->desc = *desc; 263 264 return &buf->base; 265 } 266 267 268 static void 269 pb_ondemand_manager_flush(struct pb_manager *_mgr) 270 { 271 struct pb_ondemand_manager *mgr = pb_ondemand_manager(_mgr); 272 273 mgr->provider->flush(mgr->provider); 274 } 275 276 277 static void 278 pb_ondemand_manager_destroy(struct pb_manager *_mgr) 279 { 280 struct pb_ondemand_manager *mgr = pb_ondemand_manager(_mgr); 281 282 FREE(mgr); 283 } 284 285 286 struct pb_manager * 287 pb_ondemand_manager_create(struct pb_manager *provider) 288 { 289 struct pb_ondemand_manager *mgr; 290 291 if(!provider) 292 return NULL; 293 294 mgr = CALLOC_STRUCT(pb_ondemand_manager); 295 if(!mgr) 296 return NULL; 297 298 mgr->base.destroy = pb_ondemand_manager_destroy; 299 mgr->base.create_buffer = pb_ondemand_manager_create_buffer; 300 mgr->base.flush = pb_ondemand_manager_flush; 301 302 mgr->provider = provider; 303 304 return &mgr->base; 305 } 306