Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / gallium / drivers / r600 / r600_buffer.c
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 <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 "state_tracker/drm_driver.h"
37
38 #include <xf86drm.h>
39 #include "radeon_drm.h"
40
41 #include "r600.h"
42 #include "r600_pipe.h"
43
44 static void r600_buffer_destroy(struct pipe_screen *screen,
45                                 struct pipe_resource *buf)
46 {
47         struct r600_screen *rscreen = (struct r600_screen*)screen;
48         struct r600_resource_buffer *rbuffer = r600_buffer(buf);
49
50         if (rbuffer->r.bo) {
51                 r600_bo_reference((struct radeon*)screen->winsys, &rbuffer->r.bo, NULL);
52         }
53         rbuffer->r.bo = NULL;
54         util_slab_free(&rscreen->pool_buffers, rbuffer);
55 }
56
57 static struct pipe_transfer *r600_get_transfer(struct pipe_context *ctx,
58                                                struct pipe_resource *resource,
59                                                unsigned level,
60                                                unsigned usage,
61                                                const struct pipe_box *box)
62 {
63         struct r600_pipe_context *rctx = (struct r600_pipe_context*)ctx;
64         struct pipe_transfer *transfer = util_slab_alloc(&rctx->pool_transfers);
65
66         transfer->resource = resource;
67         transfer->level = level;
68         transfer->usage = usage;
69         transfer->box = *box;
70         transfer->stride = 0;
71         transfer->layer_stride = 0;
72         transfer->data = NULL;
73
74         /* Note strides are zero, this is ok for buffers, but not for
75          * textures 2d & higher at least.
76          */
77         return transfer;
78 }
79
80 static void *r600_buffer_transfer_map(struct pipe_context *pipe,
81                                       struct pipe_transfer *transfer)
82 {
83         struct r600_resource_buffer *rbuffer = r600_buffer(transfer->resource);
84         uint8_t *data;
85
86         if (rbuffer->r.b.user_ptr)
87                 return (uint8_t*)rbuffer->r.b.user_ptr + transfer->box.x;
88
89         data = r600_bo_map((struct radeon*)pipe->winsys, rbuffer->r.bo, transfer->usage, pipe);
90         if (!data)
91                 return NULL;
92
93         return (uint8_t*)data + transfer->box.x;
94 }
95
96 static void r600_buffer_transfer_unmap(struct pipe_context *pipe,
97                                         struct pipe_transfer *transfer)
98 {
99         struct r600_resource_buffer *rbuffer = r600_buffer(transfer->resource);
100
101         if (rbuffer->r.b.user_ptr)
102                 return;
103
104         if (rbuffer->r.bo)
105                 r600_bo_unmap((struct radeon*)pipe->winsys, rbuffer->r.bo);
106 }
107
108 static void r600_buffer_transfer_flush_region(struct pipe_context *pipe,
109                                                 struct pipe_transfer *transfer,
110                                                 const struct pipe_box *box)
111 {
112 }
113
114 static void r600_transfer_destroy(struct pipe_context *ctx,
115                                   struct pipe_transfer *transfer)
116 {
117         struct r600_pipe_context *rctx = (struct r600_pipe_context*)ctx;
118         util_slab_free(&rctx->pool_transfers, transfer);
119 }
120
121 static void r600_buffer_transfer_inline_write(struct pipe_context *pipe,
122                                                 struct pipe_resource *resource,
123                                                 unsigned level,
124                                                 unsigned usage,
125                                                 const struct pipe_box *box,
126                                                 const void *data,
127                                                 unsigned stride,
128                                                 unsigned layer_stride)
129 {
130         struct radeon *ws = (struct radeon*)pipe->winsys;
131         struct r600_resource_buffer *rbuffer = r600_buffer(resource);
132         uint8_t *map = NULL;
133
134         assert(rbuffer->r.b.user_ptr == NULL);
135
136         map = r600_bo_map(ws, rbuffer->r.bo,
137                           PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD | usage,
138                           pipe);
139
140         memcpy(map + box->x, data, box->width);
141
142         if (rbuffer->r.bo)
143                 r600_bo_unmap(ws, rbuffer->r.bo);
144 }
145
146 static const struct u_resource_vtbl r600_buffer_vtbl =
147 {
148         u_default_resource_get_handle,          /* get_handle */
149         r600_buffer_destroy,                    /* resource_destroy */
150         r600_get_transfer,                      /* get_transfer */
151         r600_transfer_destroy,                  /* transfer_destroy */
152         r600_buffer_transfer_map,               /* transfer_map */
153         r600_buffer_transfer_flush_region,      /* transfer_flush_region */
154         r600_buffer_transfer_unmap,             /* transfer_unmap */
155         r600_buffer_transfer_inline_write       /* transfer_inline_write */
156 };
157
158 struct pipe_resource *r600_buffer_create(struct pipe_screen *screen,
159                                          const struct pipe_resource *templ)
160 {
161         struct r600_screen *rscreen = (struct r600_screen*)screen;
162         struct r600_resource_buffer *rbuffer;
163         struct r600_bo *bo;
164         /* XXX We probably want a different alignment for buffers and textures. */
165         unsigned alignment = 4096;
166
167         rbuffer = util_slab_alloc(&rscreen->pool_buffers);
168
169         rbuffer->magic = R600_BUFFER_MAGIC;
170         rbuffer->r.b.b.b = *templ;
171         pipe_reference_init(&rbuffer->r.b.b.b.reference, 1);
172         rbuffer->r.b.b.b.screen = screen;
173         rbuffer->r.b.b.vtbl = &r600_buffer_vtbl;
174         rbuffer->r.b.user_ptr = NULL;
175         rbuffer->r.size = rbuffer->r.b.b.b.width0;
176         rbuffer->r.bo_size = rbuffer->r.size;
177
178         bo = r600_bo((struct radeon*)screen->winsys,
179                      rbuffer->r.b.b.b.width0,
180                      alignment, rbuffer->r.b.b.b.bind,
181                      rbuffer->r.b.b.b.usage);
182
183         if (bo == NULL) {
184                 FREE(rbuffer);
185                 return NULL;
186         }
187         rbuffer->r.bo = bo;
188         return &rbuffer->r.b.b.b;
189 }
190
191 struct pipe_resource *r600_user_buffer_create(struct pipe_screen *screen,
192                                               void *ptr, unsigned bytes,
193                                               unsigned bind)
194 {
195         struct r600_screen *rscreen = (struct r600_screen*)screen;
196         struct r600_resource_buffer *rbuffer;
197
198         rbuffer = util_slab_alloc(&rscreen->pool_buffers);
199
200         rbuffer->magic = R600_BUFFER_MAGIC;
201         pipe_reference_init(&rbuffer->r.b.b.b.reference, 1);
202         rbuffer->r.b.b.vtbl = &r600_buffer_vtbl;
203         rbuffer->r.b.b.b.screen = screen;
204         rbuffer->r.b.b.b.target = PIPE_BUFFER;
205         rbuffer->r.b.b.b.format = PIPE_FORMAT_R8_UNORM;
206         rbuffer->r.b.b.b.usage = PIPE_USAGE_IMMUTABLE;
207         rbuffer->r.b.b.b.bind = bind;
208         rbuffer->r.b.b.b.width0 = bytes;
209         rbuffer->r.b.b.b.height0 = 1;
210         rbuffer->r.b.b.b.depth0 = 1;
211         rbuffer->r.b.b.b.array_size = 1;
212         rbuffer->r.b.b.b.flags = 0;
213         rbuffer->r.b.user_ptr = ptr;
214         rbuffer->r.bo = NULL;
215         rbuffer->r.bo_size = 0;
216         return &rbuffer->r.b.b.b;
217 }
218
219 struct pipe_resource *r600_buffer_from_handle(struct pipe_screen *screen,
220                                               struct winsys_handle *whandle)
221 {
222         struct radeon *rw = (struct radeon*)screen->winsys;
223         struct r600_resource *rbuffer;
224         struct r600_bo *bo = NULL;
225
226         bo = r600_bo_handle(rw, whandle->handle, NULL);
227         if (bo == NULL) {
228                 return NULL;
229         }
230
231         rbuffer = CALLOC_STRUCT(r600_resource);
232         if (rbuffer == NULL) {
233                 r600_bo_reference(rw, &bo, NULL);
234                 return NULL;
235         }
236
237         pipe_reference_init(&rbuffer->b.b.b.reference, 1);
238         rbuffer->b.b.b.target = PIPE_BUFFER;
239         rbuffer->b.b.b.screen = screen;
240         rbuffer->b.b.vtbl = &r600_buffer_vtbl;
241         rbuffer->bo = bo;
242         return &rbuffer->b.b.b;
243 }
244
245 void r600_upload_index_buffer(struct r600_pipe_context *rctx, struct r600_drawl *draw)
246 {
247         struct r600_resource_buffer *rbuffer = r600_buffer(draw->index_buffer);
248         boolean flushed;
249
250         u_upload_data(rctx->vbuf_mgr->uploader, 0,
251                       draw->info.count * draw->index_size,
252                       rbuffer->r.b.user_ptr,
253                       &draw->index_buffer_offset,
254                       &draw->index_buffer, &flushed);
255 }
256
257 void r600_upload_const_buffer(struct r600_pipe_context *rctx, struct r600_resource_buffer **rbuffer,
258                              uint32_t *const_offset)
259 {
260         if ((*rbuffer)->r.b.user_ptr) {
261                 uint8_t *ptr = (*rbuffer)->r.b.user_ptr;
262                 unsigned size = (*rbuffer)->r.b.b.b.width0;
263                 boolean flushed;
264
265                 *rbuffer = NULL;
266
267                 if (R600_BIG_ENDIAN) {
268                         uint32_t *tmpPtr;
269                         unsigned i;
270
271                         if (!(tmpPtr = malloc(size))) {
272                                 R600_ERR("Failed to allocate BE swap buffer.\n");
273                                 return;
274                         }
275
276                         for (i = 0; i < size / 4; ++i) {
277                                 tmpPtr[i] = bswap_32(((uint32_t *)ptr)[i]);
278                         }
279
280                         u_upload_data(rctx->vbuf_mgr->uploader, 0, size, tmpPtr, const_offset,
281                                       (struct pipe_resource**)rbuffer, &flushed);
282
283                         free(tmpPtr);
284                 } else {
285                         u_upload_data(rctx->vbuf_mgr->uploader, 0, size, ptr, const_offset,
286                                       (struct pipe_resource**)rbuffer, &flushed);
287                 }
288         } else {
289                 *const_offset = 0;
290         }
291 }