r300_screen_buffer.c revision 31afa7616e3c11e9874f3297ac66ebdd50a67186
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->cs_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 level, int layer) 55{ 56 return r300_buffer_is_referenced(context, buf, R300_REF_CS); 57} 58 59void r300_upload_index_buffer(struct r300_context *r300, 60 struct pipe_resource **index_buffer, 61 unsigned index_size, unsigned *start, 62 unsigned count) 63{ 64 unsigned index_offset; 65 uint8_t *ptr = r300_buffer(*index_buffer)->user_buffer; 66 boolean flushed; 67 68 *index_buffer = NULL; 69 70 u_upload_data(r300->upload_ib, 71 0, count * index_size, 72 ptr + (*start * index_size), 73 &index_offset, 74 index_buffer, &flushed); 75 76 *start = index_offset / index_size; 77 78 if (flushed || !r300->upload_ib_validated) { 79 r300->upload_ib_validated = FALSE; 80 r300->validate_buffers = TRUE; 81 } 82} 83 84void r300_upload_user_buffers(struct r300_context *r300) 85{ 86 int i, nr = r300->velems->count; 87 boolean flushed; 88 89 for (i = 0; i < nr; i++) { 90 struct pipe_vertex_buffer *vb = 91 &r300->vertex_buffer[r300->velems->velem[i].vertex_buffer_index]; 92 93 if (r300_buffer_is_user_buffer(vb->buffer)) { 94 u_upload_data(r300->upload_vb, 95 0, vb->buffer->width0, 96 r300_buffer(vb->buffer)->user_buffer, 97 &vb->buffer_offset, &vb->buffer, &flushed); 98 99 r300->vertex_arrays_dirty = TRUE; 100 101 if (flushed || !r300->upload_vb_validated) { 102 r300->upload_vb_validated = FALSE; 103 r300->validate_buffers = TRUE; 104 } 105 } 106 } 107} 108 109static void r300_buffer_destroy(struct pipe_screen *screen, 110 struct pipe_resource *buf) 111{ 112 struct r300_screen *r300screen = r300_screen(screen); 113 struct r300_buffer *rbuf = r300_buffer(buf); 114 struct r300_winsys_screen *rws = r300screen->rws; 115 116 if (rbuf->constant_buffer) 117 FREE(rbuf->constant_buffer); 118 119 if (rbuf->buf) 120 rws->buffer_reference(rws, &rbuf->buf, NULL); 121 122 util_slab_free(&r300screen->pool_buffers, rbuf); 123} 124 125static struct pipe_transfer* 126r300_buffer_get_transfer(struct pipe_context *context, 127 struct pipe_resource *resource, 128 unsigned level, 129 unsigned usage, 130 const struct pipe_box *box) 131{ 132 struct r300_context *r300 = r300_context(context); 133 struct pipe_transfer *transfer = 134 util_slab_alloc(&r300->pool_transfers); 135 136 transfer->resource = resource; 137 transfer->level = level; 138 transfer->usage = usage; 139 transfer->box = *box; 140 transfer->stride = 0; 141 transfer->layer_stride = 0; 142 transfer->data = NULL; 143 144 /* Note strides are zero, this is ok for buffers, but not for 145 * textures 2d & higher at least. 146 */ 147 return transfer; 148} 149 150static void r300_buffer_transfer_destroy(struct pipe_context *pipe, 151 struct pipe_transfer *transfer) 152{ 153 struct r300_context *r300 = r300_context(pipe); 154 util_slab_free(&r300->pool_transfers, transfer); 155} 156 157static void * 158r300_buffer_transfer_map( struct pipe_context *pipe, 159 struct pipe_transfer *transfer ) 160{ 161 struct r300_context *r300 = r300_context(pipe); 162 struct r300_screen *r300screen = r300_screen(pipe->screen); 163 struct r300_winsys_screen *rws = r300screen->rws; 164 struct r300_buffer *rbuf = r300_buffer(transfer->resource); 165 uint8_t *map; 166 boolean flush = FALSE; 167 unsigned i; 168 169 if (rbuf->user_buffer) 170 return (uint8_t *) rbuf->user_buffer + transfer->box.x; 171 if (rbuf->constant_buffer) 172 return (uint8_t *) rbuf->constant_buffer + transfer->box.x; 173 174 /* check if the mapping is to a range we already flushed */ 175 if (transfer->usage & PIPE_TRANSFER_DISCARD) { 176 for (i = 0; i < rbuf->num_ranges; i++) { 177 if ((transfer->box.x >= rbuf->ranges[i].start) && 178 (transfer->box.x < rbuf->ranges[i].end)) 179 flush = TRUE; 180 181 if (flush) { 182 /* unreference this hw buffer and allocate a new one */ 183 rws->buffer_reference(rws, &rbuf->buf, NULL); 184 185 rbuf->num_ranges = 0; 186 rbuf->buf = 187 r300screen->rws->buffer_create(r300screen->rws, 188 rbuf->b.b.width0, 16, 189 rbuf->b.b.bind, 190 rbuf->b.b.usage, 191 rbuf->domain); 192 rbuf->cs_buf = 193 r300screen->rws->buffer_get_cs_handle(r300screen->rws, 194 rbuf->buf); 195 break; 196 } 197 } 198 } 199 200 map = rws->buffer_map(rws, rbuf->buf, r300->cs, transfer->usage); 201 202 if (map == NULL) 203 return NULL; 204 205 /* map_buffer() returned a pointer to the beginning of the buffer, 206 * but transfers are expected to return a pointer to just the 207 * region specified in the box. 208 */ 209 return map + transfer->box.x; 210} 211 212static void r300_buffer_transfer_flush_region( struct pipe_context *pipe, 213 struct pipe_transfer *transfer, 214 const struct pipe_box *box) 215{ 216 struct r300_buffer *rbuf = r300_buffer(transfer->resource); 217 unsigned i; 218 unsigned offset = transfer->box.x + box->x; 219 unsigned length = box->width; 220 221 assert(box->x + box->width <= transfer->box.width); 222 223 if (rbuf->user_buffer) 224 return; 225 if (rbuf->constant_buffer) 226 return; 227 228 /* mark the range as used */ 229 for(i = 0; i < rbuf->num_ranges; ++i) { 230 if(offset <= rbuf->ranges[i].end && rbuf->ranges[i].start <= (offset+box->width)) { 231 rbuf->ranges[i].start = MIN2(rbuf->ranges[i].start, offset); 232 rbuf->ranges[i].end = MAX2(rbuf->ranges[i].end, (offset+length)); 233 return; 234 } 235 } 236 237 rbuf->ranges[rbuf->num_ranges].start = offset; 238 rbuf->ranges[rbuf->num_ranges].end = offset+length; 239 rbuf->num_ranges++; 240} 241 242static void r300_buffer_transfer_unmap( struct pipe_context *pipe, 243 struct pipe_transfer *transfer ) 244{ 245 struct r300_screen *r300screen = r300_screen(pipe->screen); 246 struct r300_winsys_screen *rws = r300screen->rws; 247 struct r300_buffer *rbuf = r300_buffer(transfer->resource); 248 249 if (rbuf->buf) { 250 rws->buffer_unmap(rws, rbuf->buf); 251 } 252} 253 254static void r300_buffer_transfer_inline_write(struct pipe_context *pipe, 255 struct pipe_resource *resource, 256 unsigned level, 257 unsigned usage, 258 const struct pipe_box *box, 259 const void *data, 260 unsigned stride, 261 unsigned layer_stride) 262{ 263 struct r300_context *r300 = r300_context(pipe); 264 struct r300_winsys_screen *rws = r300->screen->rws; 265 struct r300_buffer *rbuf = r300_buffer(resource); 266 uint8_t *map = NULL; 267 268 if (rbuf->constant_buffer) { 269 memcpy(rbuf->constant_buffer + box->x, data, box->width); 270 return; 271 } 272 assert(rbuf->user_buffer == NULL); 273 274 map = rws->buffer_map(rws, rbuf->buf, r300->cs, 275 PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD | usage); 276 277 memcpy(map + box->x, data, box->width); 278 279 rws->buffer_unmap(rws, rbuf->buf); 280} 281 282struct u_resource_vtbl r300_buffer_vtbl = 283{ 284 u_default_resource_get_handle, /* get_handle */ 285 r300_buffer_destroy, /* resource_destroy */ 286 r300_buffer_is_referenced_by_cs, /* is_buffer_referenced */ 287 r300_buffer_get_transfer, /* get_transfer */ 288 r300_buffer_transfer_destroy, /* transfer_destroy */ 289 r300_buffer_transfer_map, /* transfer_map */ 290 r300_buffer_transfer_flush_region, /* transfer_flush_region */ 291 r300_buffer_transfer_unmap, /* transfer_unmap */ 292 r300_buffer_transfer_inline_write /* transfer_inline_write */ 293}; 294 295struct pipe_resource *r300_buffer_create(struct pipe_screen *screen, 296 const struct pipe_resource *templ) 297{ 298 struct r300_screen *r300screen = r300_screen(screen); 299 struct r300_buffer *rbuf; 300 unsigned alignment = 16; 301 302 rbuf = util_slab_alloc(&r300screen->pool_buffers); 303 304 rbuf->magic = R300_BUFFER_MAGIC; 305 306 rbuf->b.b = *templ; 307 rbuf->b.vtbl = &r300_buffer_vtbl; 308 pipe_reference_init(&rbuf->b.b.reference, 1); 309 rbuf->b.b.screen = screen; 310 rbuf->domain = R300_DOMAIN_GTT; 311 rbuf->num_ranges = 0; 312 rbuf->buf = NULL; 313 rbuf->constant_buffer = NULL; 314 rbuf->user_buffer = NULL; 315 316 /* Alloc constant buffers in RAM. */ 317 if (templ->bind & PIPE_BIND_CONSTANT_BUFFER) { 318 rbuf->constant_buffer = MALLOC(templ->width0); 319 return &rbuf->b.b; 320 } 321 322 rbuf->buf = 323 r300screen->rws->buffer_create(r300screen->rws, 324 rbuf->b.b.width0, alignment, 325 rbuf->b.b.bind, rbuf->b.b.usage, 326 rbuf->domain); 327 rbuf->cs_buf = 328 r300screen->rws->buffer_get_cs_handle(r300screen->rws, rbuf->buf); 329 330 if (!rbuf->buf) { 331 util_slab_free(&r300screen->pool_buffers, rbuf); 332 return NULL; 333 } 334 335 return &rbuf->b.b; 336} 337 338struct pipe_resource *r300_user_buffer_create(struct pipe_screen *screen, 339 void *ptr, 340 unsigned bytes, 341 unsigned bind) 342{ 343 struct r300_screen *r300screen = r300_screen(screen); 344 struct r300_buffer *rbuf; 345 346 rbuf = util_slab_alloc(&r300screen->pool_buffers); 347 348 rbuf->magic = R300_BUFFER_MAGIC; 349 350 pipe_reference_init(&rbuf->b.b.reference, 1); 351 rbuf->b.vtbl = &r300_buffer_vtbl; 352 rbuf->b.b.screen = screen; 353 rbuf->b.b.target = PIPE_BUFFER; 354 rbuf->b.b.format = PIPE_FORMAT_R8_UNORM; 355 rbuf->b.b.usage = PIPE_USAGE_IMMUTABLE; 356 rbuf->b.b.bind = bind; 357 rbuf->b.b.width0 = bytes; 358 rbuf->b.b.height0 = 1; 359 rbuf->b.b.depth0 = 1; 360 rbuf->b.b.array_size = 1; 361 rbuf->b.b.flags = 0; 362 rbuf->domain = R300_DOMAIN_GTT; 363 rbuf->num_ranges = 0; 364 rbuf->buf = NULL; 365 rbuf->constant_buffer = NULL; 366 rbuf->user_buffer = ptr; 367 return &rbuf->b.b; 368} 369