r300_screen_buffer.c revision 80f24c1575688e9cd4a5a811137f43b7e0a661bb
1/* 2 * Copyright 2010 Red Hat Inc. 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 * on the rights to use, copy, modify, merge, publish, distribute, sub 8 * license, and/or sell copies of the Software, and to permit persons to whom 9 * the Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21 * USE OR OTHER DEALINGS IN THE SOFTWARE. 22 * 23 * Authors: Dave Airlie 24 */ 25 26#include <stdio.h> 27 28#include "util/u_inlines.h" 29#include "util/u_memory.h" 30#include "util/u_upload_mgr.h" 31#include "util/u_math.h" 32 33#include "r300_screen_buffer.h" 34#include "r300_winsys.h" 35 36unsigned r300_buffer_is_referenced(struct pipe_context *context, 37 struct pipe_resource *buf, 38 enum r300_reference_domain domain) 39{ 40 struct r300_context *r300 = r300_context(context); 41 struct r300_buffer *rbuf = r300_buffer(buf); 42 43 if (r300_buffer_is_user_buffer(buf)) 44 return PIPE_UNREFERENCED; 45 46 if (r300->rws->cs_is_buffer_referenced(r300->cs, rbuf->buf, domain)) 47 return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE; 48 49 return PIPE_UNREFERENCED; 50} 51 52static unsigned r300_buffer_is_referenced_by_cs(struct pipe_context *context, 53 struct pipe_resource *buf, 54 unsigned face, unsigned level) 55{ 56 return r300_buffer_is_referenced(context, buf, R300_REF_CS); 57} 58 59/* External helper, not required to implent u_resource_vtbl: 60 */ 61int r300_upload_index_buffer(struct r300_context *r300, 62 struct pipe_resource **index_buffer, 63 unsigned index_size, 64 unsigned start, 65 unsigned count, 66 unsigned *out_offset) 67{ 68 struct pipe_resource *upload_buffer = NULL; 69 unsigned index_offset = start * index_size; 70 int ret = 0; 71 72 if (r300_buffer_is_user_buffer(*index_buffer)) { 73 ret = u_upload_buffer(r300->upload_ib, 74 index_offset, 75 count * index_size, 76 *index_buffer, 77 &index_offset, 78 &upload_buffer); 79 if (ret) { 80 goto done; 81 } 82 *index_buffer = upload_buffer; 83 *out_offset = index_offset / index_size; 84 } else 85 *out_offset = start; 86 87 done: 88 // if (upload_buffer) 89 // pipe_resource_reference(&upload_buffer, NULL); 90 return ret; 91} 92 93/* External helper, not required to implement u_resource_vtbl: 94 */ 95int r300_upload_user_buffers(struct r300_context *r300) 96{ 97 enum pipe_error ret = PIPE_OK; 98 int i, nr; 99 100 nr = r300->velems->count; 101 102 for (i = 0; i < nr; i++) { 103 struct pipe_vertex_buffer *vb = 104 &r300->vertex_buffer[r300->velems->velem[i].vertex_buffer_index]; 105 106 if (r300_buffer_is_user_buffer(vb->buffer)) { 107 struct pipe_resource *upload_buffer = NULL; 108 unsigned offset = 0; /*vb->buffer_offset * 4;*/ 109 unsigned size = vb->buffer->width0; 110 unsigned upload_offset; 111 ret = u_upload_buffer(r300->upload_vb, 112 offset, size, 113 vb->buffer, 114 &upload_offset, &upload_buffer); 115 if (ret) 116 return ret; 117 118 pipe_resource_reference(&vb->buffer, NULL); 119 vb->buffer = upload_buffer; 120 vb->buffer_offset = upload_offset; 121 } 122 } 123 return ret; 124} 125 126static void r300_buffer_destroy(struct pipe_screen *screen, 127 struct pipe_resource *buf) 128{ 129 struct r300_screen *r300screen = r300_screen(screen); 130 struct r300_buffer *rbuf = r300_buffer(buf); 131 struct r300_winsys_screen *rws = r300screen->rws; 132 133 if (rbuf->constant_buffer) 134 FREE(rbuf->constant_buffer); 135 136 if (rbuf->buf) 137 rws->buffer_reference(rws, &rbuf->buf, NULL); 138 139 util_slab_free(&r300screen->pool_buffers, rbuf); 140} 141 142static struct pipe_transfer* 143r300_default_get_transfer(struct pipe_context *context, 144 struct pipe_resource *resource, 145 struct pipe_subresource sr, 146 unsigned usage, 147 const struct pipe_box *box) 148{ 149 struct r300_context *r300 = r300_context(context); 150 struct pipe_transfer *transfer = 151 util_slab_alloc(&r300->pool_transfers); 152 153 transfer->resource = resource; 154 transfer->sr = sr; 155 transfer->usage = usage; 156 transfer->box = *box; 157 transfer->stride = 0; 158 transfer->slice_stride = 0; 159 transfer->data = NULL; 160 161 /* Note strides are zero, this is ok for buffers, but not for 162 * textures 2d & higher at least. 163 */ 164 return transfer; 165} 166 167static void r300_default_transfer_destroy(struct pipe_context *pipe, 168 struct pipe_transfer *transfer) 169{ 170 struct r300_context *r300 = r300_context(pipe); 171 util_slab_free(&r300->pool_transfers, transfer); 172} 173 174static void * 175r300_buffer_transfer_map( struct pipe_context *pipe, 176 struct pipe_transfer *transfer ) 177{ 178 struct r300_context *r300 = r300_context(pipe); 179 struct r300_screen *r300screen = r300_screen(pipe->screen); 180 struct r300_winsys_screen *rws = r300screen->rws; 181 struct r300_buffer *rbuf = r300_buffer(transfer->resource); 182 uint8_t *map; 183 boolean flush = FALSE; 184 unsigned i; 185 186 if (rbuf->user_buffer) 187 return (uint8_t *) rbuf->user_buffer + transfer->box.x; 188 if (rbuf->constant_buffer) 189 return (uint8_t *) rbuf->constant_buffer + transfer->box.x; 190 191 /* check if the mapping is to a range we already flushed */ 192 if (transfer->usage & PIPE_TRANSFER_DISCARD) { 193 for (i = 0; i < rbuf->num_ranges; i++) { 194 if ((transfer->box.x >= rbuf->ranges[i].start) && 195 (transfer->box.x < rbuf->ranges[i].end)) 196 flush = TRUE; 197 198 if (flush) { 199 /* unreference this hw buffer and allocate a new one */ 200 rws->buffer_reference(rws, &rbuf->buf, NULL); 201 202 rbuf->num_ranges = 0; 203 rbuf->buf = 204 r300screen->rws->buffer_create(r300screen->rws, 205 rbuf->b.b.width0, 16, 206 rbuf->b.b.bind, 207 rbuf->b.b.usage, 208 rbuf->domain); 209 break; 210 } 211 } 212 } 213 214 map = rws->buffer_map(rws, rbuf->buf, r300->cs, transfer->usage); 215 216 if (map == NULL) 217 return NULL; 218 219 /* map_buffer() returned a pointer to the beginning of the buffer, 220 * but transfers are expected to return a pointer to just the 221 * region specified in the box. 222 */ 223 return map + transfer->box.x; 224} 225 226static void r300_buffer_transfer_flush_region( struct pipe_context *pipe, 227 struct pipe_transfer *transfer, 228 const struct pipe_box *box) 229{ 230 struct r300_buffer *rbuf = r300_buffer(transfer->resource); 231 unsigned i; 232 unsigned offset = transfer->box.x + box->x; 233 unsigned length = box->width; 234 235 assert(box->x + box->width <= transfer->box.width); 236 237 if (rbuf->user_buffer) 238 return; 239 if (rbuf->constant_buffer) 240 return; 241 242 /* mark the range as used */ 243 for(i = 0; i < rbuf->num_ranges; ++i) { 244 if(offset <= rbuf->ranges[i].end && rbuf->ranges[i].start <= (offset+box->width)) { 245 rbuf->ranges[i].start = MIN2(rbuf->ranges[i].start, offset); 246 rbuf->ranges[i].end = MAX2(rbuf->ranges[i].end, (offset+length)); 247 return; 248 } 249 } 250 251 rbuf->ranges[rbuf->num_ranges].start = offset; 252 rbuf->ranges[rbuf->num_ranges].end = offset+length; 253 rbuf->num_ranges++; 254} 255 256static void r300_buffer_transfer_unmap( struct pipe_context *pipe, 257 struct pipe_transfer *transfer ) 258{ 259 struct r300_screen *r300screen = r300_screen(pipe->screen); 260 struct r300_winsys_screen *rws = r300screen->rws; 261 struct r300_buffer *rbuf = r300_buffer(transfer->resource); 262 263 if (rbuf->buf) { 264 rws->buffer_unmap(rws, rbuf->buf); 265 } 266} 267 268struct u_resource_vtbl r300_buffer_vtbl = 269{ 270 u_default_resource_get_handle, /* get_handle */ 271 r300_buffer_destroy, /* resource_destroy */ 272 r300_buffer_is_referenced_by_cs, /* is_buffer_referenced */ 273 r300_default_get_transfer, /* get_transfer */ 274 r300_default_transfer_destroy, /* transfer_destroy */ 275 r300_buffer_transfer_map, /* transfer_map */ 276 r300_buffer_transfer_flush_region, /* transfer_flush_region */ 277 r300_buffer_transfer_unmap, /* transfer_unmap */ 278 u_default_transfer_inline_write /* transfer_inline_write */ 279}; 280 281struct pipe_resource *r300_buffer_create(struct pipe_screen *screen, 282 const struct pipe_resource *templ) 283{ 284 struct r300_screen *r300screen = r300_screen(screen); 285 struct r300_buffer *rbuf; 286 unsigned alignment = 16; 287 288 rbuf = util_slab_alloc(&r300screen->pool_buffers); 289 290 rbuf->magic = R300_BUFFER_MAGIC; 291 292 rbuf->b.b = *templ; 293 rbuf->b.vtbl = &r300_buffer_vtbl; 294 pipe_reference_init(&rbuf->b.b.reference, 1); 295 rbuf->b.b.screen = screen; 296 rbuf->domain = R300_DOMAIN_GTT; 297 rbuf->num_ranges = 0; 298 rbuf->buf = NULL; 299 rbuf->constant_buffer = NULL; 300 rbuf->user_buffer = NULL; 301 302 /* Alloc constant buffers in RAM. */ 303 if (templ->bind & PIPE_BIND_CONSTANT_BUFFER) { 304 rbuf->constant_buffer = MALLOC(templ->width0); 305 return &rbuf->b.b; 306 } 307 308 rbuf->buf = 309 r300screen->rws->buffer_create(r300screen->rws, 310 rbuf->b.b.width0, alignment, 311 rbuf->b.b.bind, rbuf->b.b.usage, 312 rbuf->domain); 313 314 if (!rbuf->buf) { 315 util_slab_free(&r300screen->pool_buffers, rbuf); 316 return NULL; 317 } 318 319 return &rbuf->b.b; 320} 321 322struct pipe_resource *r300_user_buffer_create(struct pipe_screen *screen, 323 void *ptr, 324 unsigned bytes, 325 unsigned bind) 326{ 327 struct r300_screen *r300screen = r300_screen(screen); 328 struct r300_buffer *rbuf; 329 330 rbuf = util_slab_alloc(&r300screen->pool_buffers); 331 332 rbuf->magic = R300_BUFFER_MAGIC; 333 334 pipe_reference_init(&rbuf->b.b.reference, 1); 335 rbuf->b.vtbl = &r300_buffer_vtbl; 336 rbuf->b.b.screen = screen; 337 rbuf->b.b.target = PIPE_BUFFER; 338 rbuf->b.b.format = PIPE_FORMAT_R8_UNORM; 339 rbuf->b.b.usage = PIPE_USAGE_IMMUTABLE; 340 rbuf->b.b.bind = bind; 341 rbuf->b.b.width0 = bytes; 342 rbuf->b.b.height0 = 1; 343 rbuf->b.b.depth0 = 1; 344 rbuf->b.b.flags = 0; 345 rbuf->domain = R300_DOMAIN_GTT; 346 rbuf->num_ranges = 0; 347 rbuf->buf = NULL; 348 rbuf->constant_buffer = NULL; 349 rbuf->user_buffer = ptr; 350 return &rbuf->b.b; 351} 352