r300_screen_buffer.c revision 8d0a540020f6389ca5efcd0e1fbef45a4a1f5b6a
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_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 int min_index, int max_index) 86{ 87 int i, nr = r300->velems->count; 88 unsigned count = max_index + 1 - min_index; 89 boolean flushed; 90 boolean uploaded[32] = {0}; 91 92 for (i = 0; i < nr; i++) { 93 unsigned index = r300->velems->velem[i].vertex_buffer_index; 94 struct pipe_vertex_buffer *vb = &r300->vertex_buffer[index]; 95 struct r300_buffer *userbuf = r300_buffer(vb->buffer); 96 97 if (userbuf && userbuf->user_buffer && !uploaded[index]) { 98 unsigned first, size; 99 100 if (vb->stride) { 101 first = vb->stride * min_index; 102 size = vb->stride * count; 103 } else { 104 first = 0; 105 size = r300->velems->hw_format_size[i]; 106 } 107 108 u_upload_data(r300->upload_vb, first, size, 109 userbuf->user_buffer + first, 110 &vb->buffer_offset, 111 &r300->real_vertex_buffer[index], 112 &flushed); 113 114 vb->buffer_offset -= first; 115 116 r300->vertex_arrays_dirty = TRUE; 117 118 if (flushed || !r300->upload_vb_validated) { 119 r300->upload_vb_validated = FALSE; 120 r300->validate_buffers = TRUE; 121 } 122 uploaded[index] = TRUE; 123 } else { 124 assert(r300->real_vertex_buffer[index]); 125 } 126 } 127} 128 129static void r300_buffer_destroy(struct pipe_screen *screen, 130 struct pipe_resource *buf) 131{ 132 struct r300_screen *r300screen = r300_screen(screen); 133 struct r300_buffer *rbuf = r300_buffer(buf); 134 struct r300_winsys_screen *rws = r300screen->rws; 135 136 if (rbuf->constant_buffer) 137 FREE(rbuf->constant_buffer); 138 139 if (rbuf->buf) 140 rws->buffer_reference(rws, &rbuf->buf, NULL); 141 142 util_slab_free(&r300screen->pool_buffers, rbuf); 143} 144 145static struct pipe_transfer* 146r300_buffer_get_transfer(struct pipe_context *context, 147 struct pipe_resource *resource, 148 unsigned level, 149 unsigned usage, 150 const struct pipe_box *box) 151{ 152 struct r300_context *r300 = r300_context(context); 153 struct pipe_transfer *transfer = 154 util_slab_alloc(&r300->pool_transfers); 155 156 transfer->resource = resource; 157 transfer->level = level; 158 transfer->usage = usage; 159 transfer->box = *box; 160 transfer->stride = 0; 161 transfer->layer_stride = 0; 162 transfer->data = NULL; 163 164 /* Note strides are zero, this is ok for buffers, but not for 165 * textures 2d & higher at least. 166 */ 167 return transfer; 168} 169 170static void r300_buffer_transfer_destroy(struct pipe_context *pipe, 171 struct pipe_transfer *transfer) 172{ 173 struct r300_context *r300 = r300_context(pipe); 174 util_slab_free(&r300->pool_transfers, transfer); 175} 176 177static void * 178r300_buffer_transfer_map( struct pipe_context *pipe, 179 struct pipe_transfer *transfer ) 180{ 181 struct r300_context *r300 = r300_context(pipe); 182 struct r300_screen *r300screen = r300_screen(pipe->screen); 183 struct r300_winsys_screen *rws = r300screen->rws; 184 struct r300_buffer *rbuf = r300_buffer(transfer->resource); 185 uint8_t *map; 186 187 if (rbuf->user_buffer) 188 return (uint8_t *) rbuf->user_buffer + transfer->box.x; 189 if (rbuf->constant_buffer) 190 return (uint8_t *) rbuf->constant_buffer + transfer->box.x; 191 192 map = rws->buffer_map(rws, rbuf->buf, r300->cs, transfer->usage); 193 194 if (map == NULL) 195 return NULL; 196 197 return map + transfer->box.x; 198} 199 200static void r300_buffer_transfer_flush_region( struct pipe_context *pipe, 201 struct pipe_transfer *transfer, 202 const struct pipe_box *box) 203{ 204 /* no-op */ 205} 206 207static void r300_buffer_transfer_unmap( struct pipe_context *pipe, 208 struct pipe_transfer *transfer ) 209{ 210 struct r300_screen *r300screen = r300_screen(pipe->screen); 211 struct r300_winsys_screen *rws = r300screen->rws; 212 struct r300_buffer *rbuf = r300_buffer(transfer->resource); 213 214 if (rbuf->buf) { 215 rws->buffer_unmap(rws, rbuf->buf); 216 } 217} 218 219static void r300_buffer_transfer_inline_write(struct pipe_context *pipe, 220 struct pipe_resource *resource, 221 unsigned level, 222 unsigned usage, 223 const struct pipe_box *box, 224 const void *data, 225 unsigned stride, 226 unsigned layer_stride) 227{ 228 struct r300_context *r300 = r300_context(pipe); 229 struct r300_winsys_screen *rws = r300->screen->rws; 230 struct r300_buffer *rbuf = r300_buffer(resource); 231 uint8_t *map = NULL; 232 233 if (rbuf->constant_buffer) { 234 memcpy(rbuf->constant_buffer + box->x, data, box->width); 235 return; 236 } 237 assert(rbuf->user_buffer == NULL); 238 239 map = rws->buffer_map(rws, rbuf->buf, r300->cs, 240 PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD | usage); 241 242 memcpy(map + box->x, data, box->width); 243 244 rws->buffer_unmap(rws, rbuf->buf); 245} 246 247struct u_resource_vtbl r300_buffer_vtbl = 248{ 249 u_default_resource_get_handle, /* get_handle */ 250 r300_buffer_destroy, /* resource_destroy */ 251 r300_buffer_is_referenced_by_cs, /* is_buffer_referenced */ 252 r300_buffer_get_transfer, /* get_transfer */ 253 r300_buffer_transfer_destroy, /* transfer_destroy */ 254 r300_buffer_transfer_map, /* transfer_map */ 255 r300_buffer_transfer_flush_region, /* transfer_flush_region */ 256 r300_buffer_transfer_unmap, /* transfer_unmap */ 257 r300_buffer_transfer_inline_write /* transfer_inline_write */ 258}; 259 260struct pipe_resource *r300_buffer_create(struct pipe_screen *screen, 261 const struct pipe_resource *templ) 262{ 263 struct r300_screen *r300screen = r300_screen(screen); 264 struct r300_buffer *rbuf; 265 unsigned alignment = 16; 266 267 rbuf = util_slab_alloc(&r300screen->pool_buffers); 268 269 rbuf->magic = R300_BUFFER_MAGIC; 270 271 rbuf->b.b = *templ; 272 rbuf->b.vtbl = &r300_buffer_vtbl; 273 pipe_reference_init(&rbuf->b.b.reference, 1); 274 rbuf->b.b.screen = screen; 275 rbuf->domain = R300_DOMAIN_GTT; 276 rbuf->buf = NULL; 277 rbuf->constant_buffer = NULL; 278 rbuf->user_buffer = NULL; 279 280 /* Alloc constant buffers in RAM. */ 281 if (templ->bind & PIPE_BIND_CONSTANT_BUFFER) { 282 rbuf->constant_buffer = MALLOC(templ->width0); 283 return &rbuf->b.b; 284 } 285 286 rbuf->buf = 287 r300screen->rws->buffer_create(r300screen->rws, 288 rbuf->b.b.width0, alignment, 289 rbuf->b.b.bind, rbuf->b.b.usage, 290 rbuf->domain); 291 rbuf->cs_buf = 292 r300screen->rws->buffer_get_cs_handle(r300screen->rws, rbuf->buf); 293 294 if (!rbuf->buf) { 295 util_slab_free(&r300screen->pool_buffers, rbuf); 296 return NULL; 297 } 298 299 return &rbuf->b.b; 300} 301 302struct pipe_resource *r300_user_buffer_create(struct pipe_screen *screen, 303 void *ptr, unsigned size, 304 unsigned bind) 305{ 306 struct r300_screen *r300screen = r300_screen(screen); 307 struct r300_buffer *rbuf; 308 309 rbuf = util_slab_alloc(&r300screen->pool_buffers); 310 311 rbuf->magic = R300_BUFFER_MAGIC; 312 313 pipe_reference_init(&rbuf->b.b.reference, 1); 314 rbuf->b.vtbl = &r300_buffer_vtbl; 315 rbuf->b.b.screen = screen; 316 rbuf->b.b.target = PIPE_BUFFER; 317 rbuf->b.b.format = PIPE_FORMAT_R8_UNORM; 318 rbuf->b.b.usage = PIPE_USAGE_IMMUTABLE; 319 rbuf->b.b.bind = bind; 320 rbuf->b.b.width0 = ~0; 321 rbuf->b.b.height0 = 1; 322 rbuf->b.b.depth0 = 1; 323 rbuf->b.b.array_size = 1; 324 rbuf->b.b.flags = 0; 325 rbuf->domain = R300_DOMAIN_GTT; 326 rbuf->buf = NULL; 327 rbuf->constant_buffer = NULL; 328 rbuf->user_buffer = ptr; 329 return &rbuf->b.b; 330} 331