r300_screen_buffer.c revision bb4f5fff0c782f35353e8bfc1b1227e3cc3d5986
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#include <stdio.h> 26 27#include "util/u_inlines.h" 28#include "util/u_format.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 35#include "r300_winsys.h" 36 37static unsigned r300_buffer_is_referenced(struct pipe_context *context, 38 struct pipe_resource *buf, 39 unsigned face, unsigned level) 40{ 41 struct r300_context *r300 = r300_context(context); 42 struct r300_buffer *rbuf = r300_buffer(buf); 43 44 if (r300_buffer_is_user_buffer(buf)) 45 return PIPE_UNREFERENCED; 46 47 if (r300->rws->is_buffer_referenced(r300->rws, rbuf->buf)) 48 return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE; 49 50 return PIPE_UNREFERENCED; 51} 52 53/* External helper, not required to implent u_resource_vtbl: 54 */ 55int r300_upload_index_buffer(struct r300_context *r300, 56 struct pipe_resource **index_buffer, 57 unsigned index_size, 58 unsigned start, 59 unsigned count) 60{ 61 struct pipe_resource *upload_buffer = NULL; 62 unsigned index_offset = start * index_size; 63 int ret = 0; 64 65 if (r300_buffer_is_user_buffer(*index_buffer)) { 66 ret = u_upload_buffer(r300->upload_ib, 67 index_offset, 68 count * index_size, 69 *index_buffer, 70 &index_offset, 71 &upload_buffer); 72 if (ret) { 73 goto done; 74 } 75 *index_buffer = upload_buffer; 76 } 77 done: 78 // if (upload_buffer) 79 // pipe_resource_reference(&upload_buffer, NULL); 80 return ret; 81} 82 83/* External helper, not required to implent u_resource_vtbl: 84 */ 85int r300_upload_user_buffers(struct r300_context *r300) 86{ 87 enum pipe_error ret = PIPE_OK; 88 int i, nr; 89 90 nr = r300->vertex_buffer_count; 91 92 for (i = 0; i < nr; i++) { 93 94 if (r300_buffer_is_user_buffer(r300->vertex_buffer[i].buffer)) { 95 struct pipe_resource *upload_buffer = NULL; 96 unsigned offset = 0; /*r300->vertex_buffer[i].buffer_offset * 4;*/ 97 unsigned size = r300->vertex_buffer[i].buffer->width0; 98 unsigned upload_offset; 99 ret = u_upload_buffer(r300->upload_vb, 100 offset, size, 101 r300->vertex_buffer[i].buffer, 102 &upload_offset, &upload_buffer); 103 if (ret) 104 return ret; 105 106 pipe_resource_reference(&r300->vertex_buffer[i].buffer, NULL); 107 r300->vertex_buffer[i].buffer = upload_buffer; 108 r300->vertex_buffer[i].buffer_offset = upload_offset; 109 } 110 } 111 return ret; 112} 113 114static struct r300_winsys_buffer * 115r300_winsys_buffer_create(struct r300_screen *r300screen, 116 unsigned alignment, 117 unsigned usage, 118 unsigned size) 119{ 120 struct r300_winsys_screen *rws = r300screen->rws; 121 struct r300_winsys_buffer *buf; 122 123 buf = rws->buffer_create(rws, alignment, usage, size); 124 return buf; 125} 126 127static void r300_winsys_buffer_destroy(struct r300_screen *r300screen, 128 struct r300_buffer *rbuf) 129{ 130 struct r300_winsys_screen *rws = r300screen->rws; 131 132 if (rbuf->buf) { 133 rws->buffer_reference(rws, &rbuf->buf, NULL); 134 rbuf->buf = NULL; 135 } 136} 137 138 139static void r300_buffer_destroy(struct pipe_screen *screen, 140 struct pipe_resource *buf) 141{ 142 struct r300_screen *r300screen = r300_screen(screen); 143 struct r300_buffer *rbuf = r300_buffer(buf); 144 145 r300_winsys_buffer_destroy(r300screen, rbuf); 146 FREE(rbuf); 147} 148 149static void * 150r300_buffer_map_range(struct pipe_screen *screen, 151 struct pipe_resource *buf, 152 unsigned offset, unsigned length, 153 unsigned usage ) 154{ 155 struct r300_screen *r300screen = r300_screen(screen); 156 struct r300_winsys_screen *rws = r300screen->rws; 157 struct r300_buffer *rbuf = r300_buffer(buf); 158 void *map; 159 int flush = 0; 160 int i; 161 162 if (rbuf->user_buffer) 163 return rbuf->user_buffer; 164 165 if (rbuf->b.b.bind & PIPE_BIND_CONSTANT_BUFFER) { 166 goto just_map; 167 } 168 169 /* check if the mapping is to a range we already flushed */ 170 if (usage & PIPE_TRANSFER_DISCARD) { 171 for (i = 0; i < rbuf->num_ranges; i++) { 172 173 if ((offset >= rbuf->ranges[i].start) && 174 (offset < rbuf->ranges[i].end)) 175 flush = 1; 176 177 if (flush) { 178 /* unreference this hw buffer and allocate a new one */ 179 rws->buffer_reference(rws, &rbuf->buf, NULL); 180 181 rbuf->num_ranges = 0; 182 rbuf->map = NULL; 183 rbuf->buf = r300_winsys_buffer_create(r300screen, 184 16, 185 rbuf->b.b.bind, /* XXX */ 186 rbuf->b.b.width0); 187 break; 188 } 189 } 190 } 191just_map: 192 map = rws->buffer_map(rws, rbuf->buf, usage); 193 194 return map; 195} 196 197static void 198r300_buffer_flush_mapped_range( struct pipe_screen *screen, 199 struct pipe_resource *buf, 200 unsigned offset, 201 unsigned length ) 202{ 203 struct r300_buffer *rbuf = r300_buffer(buf); 204 int i; 205 206 if (rbuf->user_buffer) 207 return; 208 209 if (rbuf->b.b.bind & PIPE_BIND_CONSTANT_BUFFER) 210 return; 211 212 /* mark the range as used */ 213 for(i = 0; i < rbuf->num_ranges; ++i) { 214 if(offset <= rbuf->ranges[i].end && rbuf->ranges[i].start <= (offset+length)) { 215 rbuf->ranges[i].start = MIN2(rbuf->ranges[i].start, offset); 216 rbuf->ranges[i].end = MAX2(rbuf->ranges[i].end, (offset+length)); 217 return; 218 } 219 } 220 221 rbuf->ranges[rbuf->num_ranges].start = offset; 222 rbuf->ranges[rbuf->num_ranges].end = offset+length; 223 rbuf->num_ranges++; 224} 225 226 227static void 228r300_buffer_unmap(struct pipe_screen *screen, 229 struct pipe_resource *buf) 230{ 231 struct r300_screen *r300screen = r300_screen(screen); 232 struct r300_winsys_screen *rws = r300screen->rws; 233 struct r300_buffer *rbuf = r300_buffer(buf); 234 235 if (rbuf->buf) { 236 rws->buffer_unmap(rws, rbuf->buf); 237 } 238} 239 240 241 242 243/* As a first step, keep the original code intact, implement buffer 244 * transfers in terms of the old map/unmap functions. 245 * 246 * Utility functions for transfer create/destroy are hooked in and 247 * just record the arguments to those functions. 248 */ 249static void * 250r300_buffer_transfer_map( struct pipe_context *pipe, 251 struct pipe_transfer *transfer ) 252{ 253 uint8_t *map = r300_buffer_map_range( pipe->screen, 254 transfer->resource, 255 transfer->box.x, 256 transfer->box.width, 257 transfer->usage ); 258 if (map == NULL) 259 return NULL; 260 261 /* map_buffer() returned a pointer to the beginning of the buffer, 262 * but transfers are expected to return a pointer to just the 263 * region specified in the box. 264 */ 265 return map + transfer->box.x; 266} 267 268 269 270static void r300_buffer_transfer_flush_region( struct pipe_context *pipe, 271 struct pipe_transfer *transfer, 272 const struct pipe_box *box) 273{ 274 assert(box->x + box->width <= transfer->box.width); 275 276 r300_buffer_flush_mapped_range(pipe->screen, 277 transfer->resource, 278 transfer->box.x + box->x, 279 box->width); 280} 281 282static void r300_buffer_transfer_unmap( struct pipe_context *pipe, 283 struct pipe_transfer *transfer ) 284{ 285 r300_buffer_unmap(pipe->screen, 286 transfer->resource); 287} 288 289 290 291 292struct u_resource_vtbl r300_buffer_vtbl = 293{ 294 u_default_resource_get_handle, /* get_handle */ 295 r300_buffer_destroy, /* resource_destroy */ 296 r300_buffer_is_referenced, /* is_buffer_referenced */ 297 u_default_get_transfer, /* get_transfer */ 298 u_default_transfer_destroy, /* transfer_destroy */ 299 r300_buffer_transfer_map, /* transfer_map */ 300 r300_buffer_transfer_flush_region, /* transfer_flush_region */ 301 r300_buffer_transfer_unmap, /* transfer_unmap */ 302 u_default_transfer_inline_write /* transfer_inline_write */ 303}; 304 305 306 307 308struct pipe_resource *r300_buffer_create(struct pipe_screen *screen, 309 const struct pipe_resource *templ) 310{ 311 struct r300_screen *r300screen = r300_screen(screen); 312 struct r300_buffer *rbuf; 313 unsigned alignment = 16; 314 315 rbuf = CALLOC_STRUCT(r300_buffer); 316 if (!rbuf) 317 goto error1; 318 319 rbuf->magic = R300_BUFFER_MAGIC; 320 321 rbuf->b.b = *templ; 322 rbuf->b.vtbl = &r300_buffer_vtbl; 323 pipe_reference_init(&rbuf->b.b.reference, 1); 324 rbuf->b.b.screen = screen; 325 326 if (rbuf->b.b.bind & R300_BIND_OQBO) 327 alignment = 4096; 328 329 rbuf->buf = r300_winsys_buffer_create(r300screen, 330 alignment, 331 rbuf->b.b.bind, 332 rbuf->b.b.width0); 333 334 if (!rbuf->buf) 335 goto error2; 336 337 return &rbuf->b.b; 338error2: 339 FREE(rbuf); 340error1: 341 return NULL; 342} 343 344 345struct pipe_resource *r300_user_buffer_create(struct pipe_screen *screen, 346 void *ptr, 347 unsigned bytes, 348 unsigned bind) 349{ 350 struct r300_buffer *rbuf; 351 352 rbuf = CALLOC_STRUCT(r300_buffer); 353 if (!rbuf) 354 goto no_rbuf; 355 356 rbuf->magic = R300_BUFFER_MAGIC; 357 358 pipe_reference_init(&rbuf->b.b.reference, 1); 359 rbuf->b.vtbl = &r300_buffer_vtbl; 360 rbuf->b.b.screen = screen; 361 rbuf->b.b.format = PIPE_FORMAT_R8_UNORM; 362 rbuf->b.b._usage = PIPE_USAGE_IMMUTABLE; 363 rbuf->b.b.bind = bind; 364 rbuf->b.b.width0 = bytes; 365 rbuf->b.b.height0 = 1; 366 rbuf->b.b.depth0 = 1; 367 368 rbuf->user_buffer = ptr; 369 return &rbuf->b.b; 370 371no_rbuf: 372 return NULL; 373} 374 375