1 /* 2 * Copyright 2010 Jerome Glisse <glisse (at) 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 (at) gmail.com> 26 */ 27 #include <byteswap.h> 28 29 #include "pipe/p_screen.h" 30 #include "util/u_format.h" 31 #include "util/u_math.h" 32 #include "util/u_inlines.h" 33 #include "util/u_memory.h" 34 #include "util/u_upload_mgr.h" 35 36 #include "r600.h" 37 #include "radeonsi_pipe.h" 38 39 static void r600_buffer_destroy(struct pipe_screen *screen, 40 struct pipe_resource *buf) 41 { 42 struct r600_screen *rscreen = (struct r600_screen*)screen; 43 struct si_resource *rbuffer = si_resource(buf); 44 45 pb_reference(&rbuffer->buf, NULL); 46 FREE(rbuffer); 47 } 48 49 static struct pipe_transfer *r600_get_transfer(struct pipe_context *ctx, 50 struct pipe_resource *resource, 51 unsigned level, 52 unsigned usage, 53 const struct pipe_box *box) 54 { 55 struct r600_context *rctx = (struct r600_context*)ctx; 56 struct pipe_transfer *transfer = util_slab_alloc(&rctx->pool_transfers); 57 58 transfer->resource = resource; 59 transfer->level = level; 60 transfer->usage = usage; 61 transfer->box = *box; 62 transfer->stride = 0; 63 transfer->layer_stride = 0; 64 transfer->data = NULL; 65 66 /* Note strides are zero, this is ok for buffers, but not for 67 * textures 2d & higher at least. 68 */ 69 return transfer; 70 } 71 72 static void *r600_buffer_transfer_map(struct pipe_context *pipe, 73 struct pipe_transfer *transfer) 74 { 75 struct si_resource *rbuffer = si_resource(transfer->resource); 76 struct r600_context *rctx = (struct r600_context*)pipe; 77 uint8_t *data; 78 79 data = rctx->ws->buffer_map(rbuffer->cs_buf, rctx->cs, transfer->usage); 80 if (!data) 81 return NULL; 82 83 return (uint8_t*)data + transfer->box.x; 84 } 85 86 static void r600_buffer_transfer_unmap(struct pipe_context *pipe, 87 struct pipe_transfer *transfer) 88 { 89 /* no-op */ 90 } 91 92 static void r600_buffer_transfer_flush_region(struct pipe_context *pipe, 93 struct pipe_transfer *transfer, 94 const struct pipe_box *box) 95 { 96 } 97 98 static void r600_transfer_destroy(struct pipe_context *ctx, 99 struct pipe_transfer *transfer) 100 { 101 struct r600_context *rctx = (struct r600_context*)ctx; 102 util_slab_free(&rctx->pool_transfers, transfer); 103 } 104 105 static const struct u_resource_vtbl r600_buffer_vtbl = 106 { 107 u_default_resource_get_handle, /* get_handle */ 108 r600_buffer_destroy, /* resource_destroy */ 109 r600_get_transfer, /* get_transfer */ 110 r600_transfer_destroy, /* transfer_destroy */ 111 r600_buffer_transfer_map, /* transfer_map */ 112 r600_buffer_transfer_flush_region, /* transfer_flush_region */ 113 r600_buffer_transfer_unmap, /* transfer_unmap */ 114 NULL /* transfer_inline_write */ 115 }; 116 117 bool si_init_resource(struct r600_screen *rscreen, 118 struct si_resource *res, 119 unsigned size, unsigned alignment, 120 unsigned bind, unsigned usage) 121 { 122 uint32_t initial_domain, domains; 123 124 /* Staging resources particpate in transfers and blits only 125 * and are used for uploads and downloads from regular 126 * resources. We generate them internally for some transfers. 127 */ 128 if (usage == PIPE_USAGE_STAGING) { 129 domains = RADEON_DOMAIN_GTT; 130 initial_domain = RADEON_DOMAIN_GTT; 131 } else { 132 domains = RADEON_DOMAIN_GTT | RADEON_DOMAIN_VRAM; 133 134 switch(usage) { 135 case PIPE_USAGE_DYNAMIC: 136 case PIPE_USAGE_STREAM: 137 case PIPE_USAGE_STAGING: 138 initial_domain = RADEON_DOMAIN_GTT; 139 break; 140 case PIPE_USAGE_DEFAULT: 141 case PIPE_USAGE_STATIC: 142 case PIPE_USAGE_IMMUTABLE: 143 default: 144 initial_domain = RADEON_DOMAIN_VRAM; 145 break; 146 } 147 } 148 149 res->buf = rscreen->ws->buffer_create(rscreen->ws, size, alignment, bind, initial_domain); 150 if (!res->buf) { 151 return false; 152 } 153 154 res->cs_buf = rscreen->ws->buffer_get_cs_handle(res->buf); 155 res->domains = domains; 156 return true; 157 } 158 159 struct pipe_resource *si_buffer_create(struct pipe_screen *screen, 160 const struct pipe_resource *templ) 161 { 162 struct r600_screen *rscreen = (struct r600_screen*)screen; 163 struct si_resource *rbuffer; 164 /* XXX We probably want a different alignment for buffers and textures. */ 165 unsigned alignment = 4096; 166 167 rbuffer = MALLOC_STRUCT(si_resource); 168 169 rbuffer->b.b = *templ; 170 pipe_reference_init(&rbuffer->b.b.reference, 1); 171 rbuffer->b.b.screen = screen; 172 rbuffer->b.vtbl = &r600_buffer_vtbl; 173 174 if (!si_init_resource(rscreen, rbuffer, templ->width0, alignment, templ->bind, templ->usage)) { 175 FREE(rbuffer); 176 return NULL; 177 } 178 return &rbuffer->b.b; 179 } 180 181 void r600_upload_index_buffer(struct r600_context *rctx, 182 struct pipe_index_buffer *ib, unsigned count) 183 { 184 u_upload_data(rctx->uploader, 0, count * ib->index_size, 185 ib->user_buffer, &ib->offset, &ib->buffer); 186 } 187 188 void r600_upload_const_buffer(struct r600_context *rctx, struct si_resource **rbuffer, 189 const uint8_t *ptr, unsigned size, 190 uint32_t *const_offset) 191 { 192 *rbuffer = NULL; 193 194 if (R600_BIG_ENDIAN) { 195 uint32_t *tmpPtr; 196 unsigned i; 197 198 if (!(tmpPtr = malloc(size))) { 199 R600_ERR("Failed to allocate BE swap buffer.\n"); 200 return; 201 } 202 203 for (i = 0; i < size / 4; ++i) { 204 tmpPtr[i] = bswap_32(((uint32_t *)ptr)[i]); 205 } 206 207 u_upload_data(rctx->uploader, 0, size, tmpPtr, const_offset, 208 (struct pipe_resource**)rbuffer); 209 210 free(tmpPtr); 211 } else { 212 u_upload_data(rctx->uploader, 0, size, ptr, const_offset, 213 (struct pipe_resource**)rbuffer); 214 } 215 } 216