1bf215546Sopenharmony_ci/************************************************************************** 2bf215546Sopenharmony_ci * 3bf215546Sopenharmony_ci * Copyright 2009 VMware, Inc. 4bf215546Sopenharmony_ci * Copyright 2016 Axel Davy <axel.davy@ens.fr> 5bf215546Sopenharmony_ci * All Rights Reserved. 6bf215546Sopenharmony_ci * 7bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 8bf215546Sopenharmony_ci * copy of this software and associated documentation files (the 9bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 10bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 11bf215546Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 12bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 13bf215546Sopenharmony_ci * the following conditions: 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the 16bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 17bf215546Sopenharmony_ci * of the Software. 18bf215546Sopenharmony_ci * 19bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 22bf215546Sopenharmony_ci * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 23bf215546Sopenharmony_ci * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24bf215546Sopenharmony_ci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25bf215546Sopenharmony_ci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26bf215546Sopenharmony_ci * 27bf215546Sopenharmony_ci **************************************************************************/ 28bf215546Sopenharmony_ci/* Adapted from u_upload_mgr. 29bf215546Sopenharmony_ci * Makes suballocations from bigger allocations, 30bf215546Sopenharmony_ci * while enabling fast mapping. */ 31bf215546Sopenharmony_ci 32bf215546Sopenharmony_ci#include "pipe/p_defines.h" 33bf215546Sopenharmony_ci#include "util/u_inlines.h" 34bf215546Sopenharmony_ci#include "pipe/p_context.h" 35bf215546Sopenharmony_ci#include "util/u_memory.h" 36bf215546Sopenharmony_ci#include "util/u_math.h" 37bf215546Sopenharmony_ci#include "util/slab.h" 38bf215546Sopenharmony_ci 39bf215546Sopenharmony_ci#include "nine_buffer_upload.h" 40bf215546Sopenharmony_ci 41bf215546Sopenharmony_ci#include "nine_debug.h" 42bf215546Sopenharmony_ci 43bf215546Sopenharmony_ci#define DBG_CHANNEL (DBG_INDEXBUFFER|DBG_VERTEXBUFFER) 44bf215546Sopenharmony_ci 45bf215546Sopenharmony_cistruct nine_buffer_group { 46bf215546Sopenharmony_ci unsigned refcount; /* How many sub-buffers live inside the buffer */ 47bf215546Sopenharmony_ci struct pipe_resource *resource; 48bf215546Sopenharmony_ci struct pipe_transfer *transfer; 49bf215546Sopenharmony_ci uint8_t *map; 50bf215546Sopenharmony_ci unsigned free_offset; /* Aligned offset to the upload buffer, pointing 51bf215546Sopenharmony_ci * at the first unused byte. */ 52bf215546Sopenharmony_ci}; 53bf215546Sopenharmony_ci 54bf215546Sopenharmony_cistruct nine_subbuffer { 55bf215546Sopenharmony_ci struct nine_buffer_group *parent; /* Can be NULL */ 56bf215546Sopenharmony_ci struct pipe_resource *resource; /* The parent resource if apply */ 57bf215546Sopenharmony_ci unsigned offset; /* Offset inside the resource */ 58bf215546Sopenharmony_ci /* If there is no parent, the resource map. Else NULL. */ 59bf215546Sopenharmony_ci struct pipe_transfer *transfer; 60bf215546Sopenharmony_ci uint8_t *map; 61bf215546Sopenharmony_ci}; 62bf215546Sopenharmony_ci 63bf215546Sopenharmony_cistruct nine_buffer_upload { 64bf215546Sopenharmony_ci struct pipe_context *pipe; 65bf215546Sopenharmony_ci struct slab_mempool buffer_pool; 66bf215546Sopenharmony_ci 67bf215546Sopenharmony_ci unsigned buffers_size; /* Size of the big allocated buffers */ 68bf215546Sopenharmony_ci unsigned num_buffers; 69bf215546Sopenharmony_ci struct nine_buffer_group *buffers; 70bf215546Sopenharmony_ci}; 71bf215546Sopenharmony_ci 72bf215546Sopenharmony_cistatic void 73bf215546Sopenharmony_cinine_upload_create_buffer_group(struct nine_buffer_upload *upload, 74bf215546Sopenharmony_ci struct nine_buffer_group *group) 75bf215546Sopenharmony_ci{ 76bf215546Sopenharmony_ci struct pipe_resource resource; 77bf215546Sopenharmony_ci struct pipe_screen *screen = upload->pipe->screen; 78bf215546Sopenharmony_ci DBG("Allocating %p %p\n", upload, group); 79bf215546Sopenharmony_ci 80bf215546Sopenharmony_ci memset(&resource, 0, sizeof(resource)); 81bf215546Sopenharmony_ci resource.target = PIPE_BUFFER; 82bf215546Sopenharmony_ci resource.format = PIPE_FORMAT_R8_UNORM; 83bf215546Sopenharmony_ci resource.bind = PIPE_BIND_VERTEX_BUFFER; 84bf215546Sopenharmony_ci resource.usage = PIPE_USAGE_STREAM; 85bf215546Sopenharmony_ci resource.width0 = upload->buffers_size; 86bf215546Sopenharmony_ci resource.height0 = 1; 87bf215546Sopenharmony_ci resource.depth0 = 1; 88bf215546Sopenharmony_ci resource.array_size = 1; 89bf215546Sopenharmony_ci resource.flags = PIPE_RESOURCE_FLAG_MAP_PERSISTENT | 90bf215546Sopenharmony_ci PIPE_RESOURCE_FLAG_MAP_COHERENT; 91bf215546Sopenharmony_ci 92bf215546Sopenharmony_ci group->refcount = 0; 93bf215546Sopenharmony_ci group->resource = screen->resource_create(screen, &resource); 94bf215546Sopenharmony_ci if (group->resource == NULL) 95bf215546Sopenharmony_ci return; 96bf215546Sopenharmony_ci 97bf215546Sopenharmony_ci group->map = pipe_buffer_map_range(upload->pipe, group->resource, 98bf215546Sopenharmony_ci 0, upload->buffers_size, 99bf215546Sopenharmony_ci PIPE_MAP_WRITE | 100bf215546Sopenharmony_ci#ifdef PIPE_ARCH_X86 101bf215546Sopenharmony_ci PIPE_MAP_ONCE | 102bf215546Sopenharmony_ci#endif 103bf215546Sopenharmony_ci PIPE_MAP_PERSISTENT | 104bf215546Sopenharmony_ci PIPE_MAP_COHERENT, 105bf215546Sopenharmony_ci &group->transfer); 106bf215546Sopenharmony_ci if (group->map == NULL) { 107bf215546Sopenharmony_ci group->transfer = NULL; 108bf215546Sopenharmony_ci pipe_resource_reference(&group->resource, NULL); 109bf215546Sopenharmony_ci return; 110bf215546Sopenharmony_ci } 111bf215546Sopenharmony_ci 112bf215546Sopenharmony_ci group->free_offset = 0; 113bf215546Sopenharmony_ci DBG("Success: %p %p\n", group->map, group->map+upload->buffers_size); 114bf215546Sopenharmony_ci} 115bf215546Sopenharmony_ci 116bf215546Sopenharmony_cistatic void 117bf215546Sopenharmony_cinine_upload_destroy_buffer_group(struct nine_buffer_upload *upload, 118bf215546Sopenharmony_ci struct nine_buffer_group *group) 119bf215546Sopenharmony_ci{ 120bf215546Sopenharmony_ci DBG("%p %p\n", upload, group); 121bf215546Sopenharmony_ci DBG("Release: %p %p\n", group->map, group->map+upload->buffers_size); 122bf215546Sopenharmony_ci assert(group->refcount == 0); 123bf215546Sopenharmony_ci 124bf215546Sopenharmony_ci if (group->transfer) 125bf215546Sopenharmony_ci pipe_buffer_unmap(upload->pipe, group->transfer); 126bf215546Sopenharmony_ci if (group->resource) 127bf215546Sopenharmony_ci pipe_resource_reference(&group->resource, NULL); 128bf215546Sopenharmony_ci group->transfer = NULL; 129bf215546Sopenharmony_ci group->map = NULL; 130bf215546Sopenharmony_ci} 131bf215546Sopenharmony_ci 132bf215546Sopenharmony_cistruct nine_buffer_upload * 133bf215546Sopenharmony_cinine_upload_create(struct pipe_context *pipe, unsigned buffers_size, 134bf215546Sopenharmony_ci unsigned num_buffers) 135bf215546Sopenharmony_ci{ 136bf215546Sopenharmony_ci struct nine_buffer_upload *upload; 137bf215546Sopenharmony_ci int i; 138bf215546Sopenharmony_ci 139bf215546Sopenharmony_ci DBG("\n"); 140bf215546Sopenharmony_ci 141bf215546Sopenharmony_ci if (!pipe->screen->get_param(pipe->screen, 142bf215546Sopenharmony_ci PIPE_CAP_BUFFER_MAP_PERSISTENT_COHERENT)) 143bf215546Sopenharmony_ci return NULL; 144bf215546Sopenharmony_ci 145bf215546Sopenharmony_ci upload = CALLOC_STRUCT(nine_buffer_upload); 146bf215546Sopenharmony_ci 147bf215546Sopenharmony_ci if (!upload) 148bf215546Sopenharmony_ci return NULL; 149bf215546Sopenharmony_ci 150bf215546Sopenharmony_ci slab_create(&upload->buffer_pool, sizeof(struct nine_subbuffer), 4096); 151bf215546Sopenharmony_ci 152bf215546Sopenharmony_ci upload->pipe = pipe; 153bf215546Sopenharmony_ci upload->buffers_size = align(buffers_size, 4096); 154bf215546Sopenharmony_ci upload->num_buffers = num_buffers; 155bf215546Sopenharmony_ci 156bf215546Sopenharmony_ci upload->buffers = CALLOC(num_buffers, sizeof(struct nine_buffer_group)); 157bf215546Sopenharmony_ci if (!upload->buffers) 158bf215546Sopenharmony_ci goto buffers_fail; 159bf215546Sopenharmony_ci 160bf215546Sopenharmony_ci for (i = 0; i < num_buffers; i++) 161bf215546Sopenharmony_ci nine_upload_create_buffer_group(upload, &upload->buffers[i]); 162bf215546Sopenharmony_ci 163bf215546Sopenharmony_ci return upload; 164bf215546Sopenharmony_ci 165bf215546Sopenharmony_cibuffers_fail: 166bf215546Sopenharmony_ci slab_destroy(&upload->buffer_pool); 167bf215546Sopenharmony_ci FREE(upload); 168bf215546Sopenharmony_ci return NULL; 169bf215546Sopenharmony_ci} 170bf215546Sopenharmony_ci 171bf215546Sopenharmony_civoid 172bf215546Sopenharmony_cinine_upload_destroy(struct nine_buffer_upload *upload) 173bf215546Sopenharmony_ci{ 174bf215546Sopenharmony_ci int i; 175bf215546Sopenharmony_ci 176bf215546Sopenharmony_ci DBG("%p\n", upload); 177bf215546Sopenharmony_ci 178bf215546Sopenharmony_ci for (i = 0; i < upload->num_buffers; i++) 179bf215546Sopenharmony_ci nine_upload_destroy_buffer_group(upload, &upload->buffers[i]); 180bf215546Sopenharmony_ci slab_destroy(&upload->buffer_pool); 181bf215546Sopenharmony_ci FREE(upload); 182bf215546Sopenharmony_ci} 183bf215546Sopenharmony_ci 184bf215546Sopenharmony_cistruct nine_subbuffer * 185bf215546Sopenharmony_cinine_upload_create_buffer(struct nine_buffer_upload *upload, 186bf215546Sopenharmony_ci unsigned buffer_size) 187bf215546Sopenharmony_ci{ 188bf215546Sopenharmony_ci struct nine_subbuffer *buf = slab_alloc_st(&upload->buffer_pool); 189bf215546Sopenharmony_ci struct nine_buffer_group *group = NULL; 190bf215546Sopenharmony_ci unsigned size = align(buffer_size, 4096); 191bf215546Sopenharmony_ci int i = 0; 192bf215546Sopenharmony_ci 193bf215546Sopenharmony_ci DBG("%p %d\n", upload, buffer_size); 194bf215546Sopenharmony_ci 195bf215546Sopenharmony_ci if (!buf) 196bf215546Sopenharmony_ci return NULL; 197bf215546Sopenharmony_ci 198bf215546Sopenharmony_ci for (i = 0; i < upload->num_buffers; i++) { 199bf215546Sopenharmony_ci group = &upload->buffers[i]; 200bf215546Sopenharmony_ci if (group->resource && 201bf215546Sopenharmony_ci group->free_offset + size <= upload->buffers_size) 202bf215546Sopenharmony_ci break; 203bf215546Sopenharmony_ci } 204bf215546Sopenharmony_ci 205bf215546Sopenharmony_ci if (i == upload->num_buffers) { 206bf215546Sopenharmony_ci /* Allocate lonely buffer */ 207bf215546Sopenharmony_ci struct pipe_resource resource; 208bf215546Sopenharmony_ci struct pipe_screen *screen = upload->pipe->screen; 209bf215546Sopenharmony_ci 210bf215546Sopenharmony_ci DBG("Allocating buffer\n"); 211bf215546Sopenharmony_ci buf->parent = NULL; 212bf215546Sopenharmony_ci 213bf215546Sopenharmony_ci memset(&resource, 0, sizeof(resource)); 214bf215546Sopenharmony_ci resource.target = PIPE_BUFFER; 215bf215546Sopenharmony_ci resource.format = PIPE_FORMAT_R8_UNORM; 216bf215546Sopenharmony_ci resource.bind = PIPE_BIND_VERTEX_BUFFER; 217bf215546Sopenharmony_ci resource.usage = PIPE_USAGE_STREAM; 218bf215546Sopenharmony_ci resource.width0 = buffer_size; 219bf215546Sopenharmony_ci resource.height0 = 1; 220bf215546Sopenharmony_ci resource.depth0 = 1; 221bf215546Sopenharmony_ci resource.array_size = 1; 222bf215546Sopenharmony_ci resource.flags = PIPE_RESOURCE_FLAG_MAP_PERSISTENT | 223bf215546Sopenharmony_ci PIPE_RESOURCE_FLAG_MAP_COHERENT; 224bf215546Sopenharmony_ci 225bf215546Sopenharmony_ci buf->resource = screen->resource_create(screen, &resource); 226bf215546Sopenharmony_ci if (buf->resource == NULL) { 227bf215546Sopenharmony_ci slab_free_st(&upload->buffer_pool, buf); 228bf215546Sopenharmony_ci return NULL; 229bf215546Sopenharmony_ci } 230bf215546Sopenharmony_ci 231bf215546Sopenharmony_ci buf->map = pipe_buffer_map_range(upload->pipe, buf->resource, 232bf215546Sopenharmony_ci 0, buffer_size, 233bf215546Sopenharmony_ci PIPE_MAP_WRITE | 234bf215546Sopenharmony_ci#ifdef PIPE_ARCH_X86 235bf215546Sopenharmony_ci PIPE_MAP_ONCE | 236bf215546Sopenharmony_ci#endif 237bf215546Sopenharmony_ci PIPE_MAP_PERSISTENT | 238bf215546Sopenharmony_ci PIPE_MAP_COHERENT, 239bf215546Sopenharmony_ci &buf->transfer); 240bf215546Sopenharmony_ci if (buf->map == NULL) { 241bf215546Sopenharmony_ci pipe_resource_reference(&buf->resource, NULL); 242bf215546Sopenharmony_ci slab_free_st(&upload->buffer_pool, buf); 243bf215546Sopenharmony_ci return NULL; 244bf215546Sopenharmony_ci } 245bf215546Sopenharmony_ci buf->offset = 0; 246bf215546Sopenharmony_ci return buf; 247bf215546Sopenharmony_ci } 248bf215546Sopenharmony_ci 249bf215546Sopenharmony_ci DBG("Using buffer group %d\n", i); 250bf215546Sopenharmony_ci 251bf215546Sopenharmony_ci buf->parent = group; 252bf215546Sopenharmony_ci buf->resource = NULL; 253bf215546Sopenharmony_ci pipe_resource_reference(&buf->resource, group->resource); 254bf215546Sopenharmony_ci buf->offset = group->free_offset; 255bf215546Sopenharmony_ci 256bf215546Sopenharmony_ci group->free_offset += size; 257bf215546Sopenharmony_ci group->refcount += 1; 258bf215546Sopenharmony_ci 259bf215546Sopenharmony_ci return buf; 260bf215546Sopenharmony_ci} 261bf215546Sopenharmony_ci 262bf215546Sopenharmony_civoid 263bf215546Sopenharmony_cinine_upload_release_buffer(struct nine_buffer_upload *upload, 264bf215546Sopenharmony_ci struct nine_subbuffer *buf) 265bf215546Sopenharmony_ci{ 266bf215546Sopenharmony_ci DBG("%p %p %p\n", upload, buf, buf->parent); 267bf215546Sopenharmony_ci 268bf215546Sopenharmony_ci if (buf->parent) { 269bf215546Sopenharmony_ci pipe_resource_reference(&buf->resource, NULL); 270bf215546Sopenharmony_ci buf->parent->refcount--; 271bf215546Sopenharmony_ci if (buf->parent->refcount == 0) { 272bf215546Sopenharmony_ci /* Allocate new buffer */ 273bf215546Sopenharmony_ci nine_upload_destroy_buffer_group(upload, buf->parent); 274bf215546Sopenharmony_ci nine_upload_create_buffer_group(upload, buf->parent); 275bf215546Sopenharmony_ci } 276bf215546Sopenharmony_ci } else { 277bf215546Sopenharmony_ci /* lonely buffer */ 278bf215546Sopenharmony_ci if (buf->transfer) 279bf215546Sopenharmony_ci pipe_buffer_unmap(upload->pipe, buf->transfer); 280bf215546Sopenharmony_ci pipe_resource_reference(&buf->resource, NULL); 281bf215546Sopenharmony_ci } 282bf215546Sopenharmony_ci 283bf215546Sopenharmony_ci slab_free_st(&upload->buffer_pool, buf); 284bf215546Sopenharmony_ci} 285bf215546Sopenharmony_ci 286bf215546Sopenharmony_ciuint8_t * 287bf215546Sopenharmony_cinine_upload_buffer_get_map(struct nine_subbuffer *buf) 288bf215546Sopenharmony_ci{ 289bf215546Sopenharmony_ci if (buf->parent) { 290bf215546Sopenharmony_ci DBG("%d\n", buf->parent->refcount); 291bf215546Sopenharmony_ci return buf->parent->map + buf->offset; 292bf215546Sopenharmony_ci } 293bf215546Sopenharmony_ci /* lonely buffer */ 294bf215546Sopenharmony_ci return buf->map; 295bf215546Sopenharmony_ci} 296bf215546Sopenharmony_ci 297bf215546Sopenharmony_cistruct pipe_resource * 298bf215546Sopenharmony_cinine_upload_buffer_resource_and_offset(struct nine_subbuffer *buf, 299bf215546Sopenharmony_ci unsigned *offset) 300bf215546Sopenharmony_ci{ 301bf215546Sopenharmony_ci *offset = buf->offset; 302bf215546Sopenharmony_ci return buf->resource; 303bf215546Sopenharmony_ci} 304