r600_buffer.c revision 05ea705c7c6212d16fcc9bcf04619ffd4311bb03
1/* 2 * Copyright 2010 Jerome Glisse <glisse@freedesktop.org> 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: 24 * Jerome Glisse 25 * Corbin Simpson <MostAwesomeDude@gmail.com> 26 */ 27#include "r600_pipe.h" 28#include "util/u_upload_mgr.h" 29#include "util/u_memory.h" 30 31static void r600_buffer_destroy(struct pipe_screen *screen, 32 struct pipe_resource *buf) 33{ 34 struct r600_resource *rbuffer = r600_resource(buf); 35 36 pb_reference(&rbuffer->buf, NULL); 37 FREE(rbuffer); 38} 39 40static struct pipe_transfer *r600_get_transfer(struct pipe_context *ctx, 41 struct pipe_resource *resource, 42 unsigned level, 43 unsigned usage, 44 const struct pipe_box *box) 45{ 46 struct r600_context *rctx = (struct r600_context*)ctx; 47 struct pipe_transfer *transfer = util_slab_alloc(&rctx->pool_transfers); 48 49 transfer->resource = resource; 50 transfer->level = level; 51 transfer->usage = usage; 52 transfer->box = *box; 53 transfer->stride = 0; 54 transfer->layer_stride = 0; 55 transfer->data = NULL; 56 57 /* Note strides are zero, this is ok for buffers, but not for 58 * textures 2d & higher at least. 59 */ 60 return transfer; 61} 62 63static void r600_set_constants_dirty_if_bound(struct r600_context *rctx, 64 struct r600_constbuf_state *state, 65 struct r600_resource *rbuffer) 66{ 67 bool found = false; 68 uint32_t mask = state->enabled_mask; 69 70 while (mask) { 71 unsigned i = u_bit_scan(&mask); 72 if (state->cb[i].buffer == &rbuffer->b.b) { 73 found = true; 74 state->dirty_mask |= 1 << i; 75 } 76 } 77 if (found) { 78 r600_constant_buffers_dirty(rctx, state); 79 } 80} 81 82static void *r600_buffer_transfer_map(struct pipe_context *pipe, 83 struct pipe_transfer *transfer) 84{ 85 struct r600_resource *rbuffer = r600_resource(transfer->resource); 86 struct r600_context *rctx = (struct r600_context*)pipe; 87 uint8_t *data; 88 89 if (transfer->usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE && 90 !(transfer->usage & PIPE_TRANSFER_UNSYNCHRONIZED)) { 91 assert(transfer->usage & PIPE_TRANSFER_WRITE); 92 93 /* Check if mapping this buffer would cause waiting for the GPU. */ 94 if (rctx->ws->cs_is_buffer_referenced(rctx->cs, rbuffer->cs_buf, RADEON_USAGE_READWRITE) || 95 rctx->ws->buffer_is_busy(rbuffer->buf, RADEON_USAGE_READWRITE)) { 96 unsigned i; 97 98 /* Discard the buffer. */ 99 pb_reference(&rbuffer->buf, NULL); 100 101 /* Create a new one in the same pipe_resource. */ 102 /* XXX We probably want a different alignment for buffers and textures. */ 103 r600_init_resource(rctx->screen, rbuffer, rbuffer->b.b.width0, 4096, 104 rbuffer->b.b.bind, rbuffer->b.b.usage); 105 106 /* We changed the buffer, now we need to bind it where the old one was bound. */ 107 /* Vertex buffers. */ 108 for (i = 0; i < rctx->nr_vertex_buffers; i++) { 109 if (rctx->vertex_buffer[i].buffer == &rbuffer->b.b) { 110 r600_inval_vertex_cache(rctx); 111 r600_atom_dirty(rctx, &rctx->vertex_buffer_state); 112 } 113 } 114 /* Streamout buffers. */ 115 for (i = 0; i < rctx->num_so_targets; i++) { 116 if (rctx->so_targets[i]->b.buffer == &rbuffer->b.b) { 117 r600_context_streamout_end(rctx); 118 rctx->streamout_start = TRUE; 119 rctx->streamout_append_bitmask = ~0; 120 } 121 } 122 /* Constant buffers. */ 123 r600_set_constants_dirty_if_bound(rctx, &rctx->vs_constbuf_state, rbuffer); 124 r600_set_constants_dirty_if_bound(rctx, &rctx->ps_constbuf_state, rbuffer); 125 } 126 } 127 128 data = rctx->ws->buffer_map(rbuffer->cs_buf, rctx->cs, transfer->usage); 129 if (!data) 130 return NULL; 131 132 return (uint8_t*)data + transfer->box.x; 133} 134 135static void r600_buffer_transfer_unmap(struct pipe_context *pipe, 136 struct pipe_transfer *transfer) 137{ 138 /* no-op */ 139} 140 141static void r600_transfer_destroy(struct pipe_context *ctx, 142 struct pipe_transfer *transfer) 143{ 144 struct r600_context *rctx = (struct r600_context*)ctx; 145 util_slab_free(&rctx->pool_transfers, transfer); 146} 147 148static const struct u_resource_vtbl r600_buffer_vtbl = 149{ 150 u_default_resource_get_handle, /* get_handle */ 151 r600_buffer_destroy, /* resource_destroy */ 152 r600_get_transfer, /* get_transfer */ 153 r600_transfer_destroy, /* transfer_destroy */ 154 r600_buffer_transfer_map, /* transfer_map */ 155 NULL, /* transfer_flush_region */ 156 r600_buffer_transfer_unmap, /* transfer_unmap */ 157 NULL /* transfer_inline_write */ 158}; 159 160bool r600_init_resource(struct r600_screen *rscreen, 161 struct r600_resource *res, 162 unsigned size, unsigned alignment, 163 unsigned bind, unsigned usage) 164{ 165 uint32_t initial_domain, domains; 166 167 /* Staging resources particpate in transfers and blits only 168 * and are used for uploads and downloads from regular 169 * resources. We generate them internally for some transfers. 170 */ 171 if (usage == PIPE_USAGE_STAGING) { 172 domains = RADEON_DOMAIN_GTT; 173 initial_domain = RADEON_DOMAIN_GTT; 174 } else { 175 domains = RADEON_DOMAIN_GTT | RADEON_DOMAIN_VRAM; 176 177 switch(usage) { 178 case PIPE_USAGE_DYNAMIC: 179 case PIPE_USAGE_STREAM: 180 case PIPE_USAGE_STAGING: 181 initial_domain = RADEON_DOMAIN_GTT; 182 break; 183 case PIPE_USAGE_DEFAULT: 184 case PIPE_USAGE_STATIC: 185 case PIPE_USAGE_IMMUTABLE: 186 default: 187 initial_domain = RADEON_DOMAIN_VRAM; 188 break; 189 } 190 } 191 192 res->buf = rscreen->ws->buffer_create(rscreen->ws, size, alignment, bind, initial_domain); 193 if (!res->buf) { 194 return false; 195 } 196 197 res->cs_buf = rscreen->ws->buffer_get_cs_handle(res->buf); 198 res->domains = domains; 199 return true; 200} 201 202struct pipe_resource *r600_buffer_create(struct pipe_screen *screen, 203 const struct pipe_resource *templ) 204{ 205 struct r600_screen *rscreen = (struct r600_screen*)screen; 206 struct r600_resource *rbuffer; 207 /* XXX We probably want a different alignment for buffers and textures. */ 208 unsigned alignment = 4096; 209 210 rbuffer = MALLOC_STRUCT(r600_resource); 211 212 rbuffer->b.b = *templ; 213 pipe_reference_init(&rbuffer->b.b.reference, 1); 214 rbuffer->b.b.screen = screen; 215 rbuffer->b.vtbl = &r600_buffer_vtbl; 216 217 if (!r600_init_resource(rscreen, rbuffer, templ->width0, alignment, templ->bind, templ->usage)) { 218 FREE(rbuffer); 219 return NULL; 220 } 221 return &rbuffer->b.b; 222} 223