r300_screen_buffer.c revision 7a1b5c937fa32968a04a11649e456a1ef8c5b442
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_format.h" 30#include "util/u_memory.h" 31#include "util/u_upload_mgr.h" 32#include "util/u_math.h" 33 34#include "r300_screen_buffer.h" 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, R300_REF_CS)) 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 implement 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 if (r300_buffer_is_user_buffer(r300->vertex_buffer[i].buffer)) { 94 struct pipe_resource *upload_buffer = NULL; 95 unsigned offset = 0; /*r300->vertex_buffer[i].buffer_offset * 4;*/ 96 unsigned size = r300->vertex_buffer[i].buffer->width0; 97 unsigned upload_offset; 98 ret = u_upload_buffer(r300->upload_vb, 99 offset, size, 100 r300->vertex_buffer[i].buffer, 101 &upload_offset, &upload_buffer); 102 if (ret) 103 return ret; 104 105 pipe_resource_reference(&r300->vertex_buffer[i].buffer, NULL); 106 r300->vertex_buffer[i].buffer = upload_buffer; 107 r300->vertex_buffer[i].buffer_offset = upload_offset; 108 } 109 } 110 return ret; 111} 112 113static struct r300_winsys_buffer * 114r300_winsys_buffer_create(struct r300_screen *r300screen, 115 unsigned alignment, 116 unsigned usage, 117 unsigned size) 118{ 119 struct r300_winsys_screen *rws = r300screen->rws; 120 struct r300_winsys_buffer *buf; 121 122 buf = rws->buffer_create(rws, alignment, usage, size); 123 return buf; 124} 125 126static void r300_winsys_buffer_destroy(struct r300_screen *r300screen, 127 struct r300_buffer *rbuf) 128{ 129 struct r300_winsys_screen *rws = r300screen->rws; 130 131 if (rbuf->buf) { 132 rws->buffer_reference(rws, &rbuf->buf, NULL); 133 rbuf->buf = NULL; 134 } 135} 136 137static void r300_buffer_destroy(struct pipe_screen *screen, 138 struct pipe_resource *buf) 139{ 140 struct r300_screen *r300screen = r300_screen(screen); 141 struct r300_buffer *rbuf = r300_buffer(buf); 142 143 r300_winsys_buffer_destroy(r300screen, rbuf); 144 FREE(rbuf); 145} 146 147static void * 148r300_buffer_transfer_map( struct pipe_context *pipe, 149 struct pipe_transfer *transfer ) 150{ 151 struct r300_screen *r300screen = r300_screen(pipe->screen); 152 struct r300_winsys_screen *rws = r300screen->rws; 153 struct r300_buffer *rbuf = r300_buffer(transfer->resource); 154 uint8_t *map; 155 boolean flush = FALSE; 156 unsigned i; 157 158 if (rbuf->user_buffer) 159 return (uint8_t *) rbuf->user_buffer + transfer->box.x; 160 161 if (rbuf->b.b.bind & PIPE_BIND_CONSTANT_BUFFER) { 162 goto just_map; 163 } 164 165 /* check if the mapping is to a range we already flushed */ 166 if (transfer->usage & PIPE_TRANSFER_DISCARD) { 167 for (i = 0; i < rbuf->num_ranges; i++) { 168 if ((transfer->box.x >= rbuf->ranges[i].start) && 169 (transfer->box.x < rbuf->ranges[i].end)) 170 flush = TRUE; 171 172 if (flush) { 173 /* unreference this hw buffer and allocate a new one */ 174 rws->buffer_reference(rws, &rbuf->buf, NULL); 175 176 rbuf->num_ranges = 0; 177 rbuf->map = NULL; 178 rbuf->buf = r300_winsys_buffer_create(r300screen, 179 16, 180 rbuf->b.b.bind, /* XXX */ 181 rbuf->b.b.width0); 182 break; 183 } 184 } 185 } 186just_map: 187 map = rws->buffer_map(rws, rbuf->buf, transfer->usage); 188 189 if (map == NULL) 190 return NULL; 191 192 /* map_buffer() returned a pointer to the beginning of the buffer, 193 * but transfers are expected to return a pointer to just the 194 * region specified in the box. 195 */ 196 return map + transfer->box.x; 197} 198 199static void r300_buffer_transfer_flush_region( struct pipe_context *pipe, 200 struct pipe_transfer *transfer, 201 const struct pipe_box *box) 202{ 203 struct r300_buffer *rbuf = r300_buffer(transfer->resource); 204 unsigned i; 205 unsigned offset = transfer->box.x + box->x; 206 unsigned length = box->width; 207 208 assert(box->x + box->width <= transfer->box.width); 209 210 if (rbuf->user_buffer) 211 return; 212 213 if (rbuf->b.b.bind & PIPE_BIND_CONSTANT_BUFFER) 214 return; 215 216 /* mark the range as used */ 217 for(i = 0; i < rbuf->num_ranges; ++i) { 218 if(offset <= rbuf->ranges[i].end && rbuf->ranges[i].start <= (offset+box->width)) { 219 rbuf->ranges[i].start = MIN2(rbuf->ranges[i].start, offset); 220 rbuf->ranges[i].end = MAX2(rbuf->ranges[i].end, (offset+length)); 221 return; 222 } 223 } 224 225 rbuf->ranges[rbuf->num_ranges].start = offset; 226 rbuf->ranges[rbuf->num_ranges].end = offset+length; 227 rbuf->num_ranges++; 228} 229 230static void r300_buffer_transfer_unmap( struct pipe_context *pipe, 231 struct pipe_transfer *transfer ) 232{ 233 struct r300_screen *r300screen = r300_screen(pipe->screen); 234 struct r300_winsys_screen *rws = r300screen->rws; 235 struct r300_buffer *rbuf = r300_buffer(transfer->resource); 236 237 if (rbuf->buf) { 238 rws->buffer_unmap(rws, rbuf->buf); 239 } 240} 241 242struct u_resource_vtbl r300_buffer_vtbl = 243{ 244 u_default_resource_get_handle, /* get_handle */ 245 r300_buffer_destroy, /* resource_destroy */ 246 r300_buffer_is_referenced, /* is_buffer_referenced */ 247 u_default_get_transfer, /* get_transfer */ 248 u_default_transfer_destroy, /* transfer_destroy */ 249 r300_buffer_transfer_map, /* transfer_map */ 250 r300_buffer_transfer_flush_region, /* transfer_flush_region */ 251 r300_buffer_transfer_unmap, /* transfer_unmap */ 252 u_default_transfer_inline_write /* transfer_inline_write */ 253}; 254 255struct pipe_resource *r300_buffer_create(struct pipe_screen *screen, 256 const struct pipe_resource *templ) 257{ 258 struct r300_screen *r300screen = r300_screen(screen); 259 struct r300_buffer *rbuf; 260 unsigned alignment = 16; 261 262 rbuf = CALLOC_STRUCT(r300_buffer); 263 if (!rbuf) 264 goto error1; 265 266 rbuf->magic = R300_BUFFER_MAGIC; 267 268 rbuf->b.b = *templ; 269 rbuf->b.vtbl = &r300_buffer_vtbl; 270 pipe_reference_init(&rbuf->b.b.reference, 1); 271 rbuf->b.b.screen = screen; 272 273 if (rbuf->b.b.bind & R300_BIND_OQBO) 274 alignment = 4096; 275 276 rbuf->buf = r300_winsys_buffer_create(r300screen, 277 alignment, 278 rbuf->b.b.bind, 279 rbuf->b.b.width0); 280 281 if (!rbuf->buf) 282 goto error2; 283 284 return &rbuf->b.b; 285error2: 286 FREE(rbuf); 287error1: 288 return NULL; 289} 290 291struct pipe_resource *r300_user_buffer_create(struct pipe_screen *screen, 292 void *ptr, 293 unsigned bytes, 294 unsigned bind) 295{ 296 struct r300_buffer *rbuf; 297 298 rbuf = CALLOC_STRUCT(r300_buffer); 299 if (!rbuf) 300 goto no_rbuf; 301 302 rbuf->magic = R300_BUFFER_MAGIC; 303 304 pipe_reference_init(&rbuf->b.b.reference, 1); 305 rbuf->b.vtbl = &r300_buffer_vtbl; 306 rbuf->b.b.screen = screen; 307 rbuf->b.b.format = PIPE_FORMAT_R8_UNORM; 308 rbuf->b.b._usage = PIPE_USAGE_IMMUTABLE; 309 rbuf->b.b.bind = bind; 310 rbuf->b.b.width0 = bytes; 311 rbuf->b.b.height0 = 1; 312 rbuf->b.b.depth0 = 1; 313 314 rbuf->user_buffer = ptr; 315 return &rbuf->b.b; 316 317no_rbuf: 318 return NULL; 319} 320