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