r300_screen_buffer.c revision 93f4e3cb6c1ca303ee1f5c2a2491a8eff33f2633
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
35void r300_upload_index_buffer(struct r300_context *r300,
36			      struct pipe_resource **index_buffer,
37			      unsigned index_size, unsigned *start,
38			      unsigned count, uint8_t *ptr)
39{
40    unsigned index_offset;
41    boolean flushed;
42
43    *index_buffer = NULL;
44
45    u_upload_data(r300->vbuf_mgr->uploader,
46                  0, count * index_size,
47                  ptr + (*start * index_size),
48                  &index_offset,
49                  index_buffer, &flushed);
50
51    *start = index_offset / index_size;
52}
53
54static void r300_buffer_destroy(struct pipe_screen *screen,
55				struct pipe_resource *buf)
56{
57    struct r300_screen *r300screen = r300_screen(screen);
58    struct r300_resource *rbuf = r300_resource(buf);
59
60    if (rbuf->constant_buffer)
61        FREE(rbuf->constant_buffer);
62
63    if (rbuf->buf)
64        pb_reference(&rbuf->buf, NULL);
65
66    util_slab_free(&r300screen->pool_buffers, rbuf);
67}
68
69static struct pipe_transfer*
70r300_buffer_get_transfer(struct pipe_context *context,
71                         struct pipe_resource *resource,
72                         unsigned level,
73                         unsigned usage,
74                         const struct pipe_box *box)
75{
76   struct r300_context *r300 = r300_context(context);
77   struct pipe_transfer *transfer =
78         util_slab_alloc(&r300->pool_transfers);
79
80   transfer->resource = resource;
81   transfer->level = level;
82   transfer->usage = usage;
83   transfer->box = *box;
84   transfer->stride = 0;
85   transfer->layer_stride = 0;
86   transfer->data = NULL;
87
88   /* Note strides are zero, this is ok for buffers, but not for
89    * textures 2d & higher at least.
90    */
91   return transfer;
92}
93
94static void r300_buffer_transfer_destroy(struct pipe_context *pipe,
95                                         struct pipe_transfer *transfer)
96{
97   struct r300_context *r300 = r300_context(pipe);
98   util_slab_free(&r300->pool_transfers, transfer);
99}
100
101static void *
102r300_buffer_transfer_map( struct pipe_context *pipe,
103			  struct pipe_transfer *transfer )
104{
105    struct r300_context *r300 = r300_context(pipe);
106    struct r300_screen *r300screen = r300_screen(pipe->screen);
107    struct radeon_winsys *rws = r300screen->rws;
108    struct r300_resource *rbuf = r300_resource(transfer->resource);
109    uint8_t *map;
110
111    if (rbuf->b.user_ptr)
112        return (uint8_t *) rbuf->b.user_ptr + transfer->box.x;
113    if (rbuf->constant_buffer)
114        return (uint8_t *) rbuf->constant_buffer + transfer->box.x;
115
116    map = rws->buffer_map(rbuf->buf, r300->cs, transfer->usage);
117
118    if (map == NULL)
119        return NULL;
120
121    return map + transfer->box.x;
122}
123
124static void r300_buffer_transfer_unmap( struct pipe_context *pipe,
125			    struct pipe_transfer *transfer )
126{
127    struct r300_screen *r300screen = r300_screen(pipe->screen);
128    struct radeon_winsys *rws = r300screen->rws;
129    struct r300_resource *rbuf = r300_resource(transfer->resource);
130
131    if (rbuf->buf) {
132        rws->buffer_unmap(rbuf->buf);
133    }
134}
135
136static void r300_buffer_transfer_inline_write(struct pipe_context *pipe,
137                                              struct pipe_resource *resource,
138                                              unsigned level,
139                                              unsigned usage,
140                                              const struct pipe_box *box,
141                                              const void *data,
142                                              unsigned stride,
143                                              unsigned layer_stride)
144{
145    struct r300_context *r300 = r300_context(pipe);
146    struct radeon_winsys *rws = r300->screen->rws;
147    struct r300_resource *rbuf = r300_resource(resource);
148    uint8_t *map = NULL;
149
150    if (rbuf->constant_buffer) {
151        memcpy(rbuf->constant_buffer + box->x, data, box->width);
152        return;
153    }
154    assert(rbuf->b.user_ptr == NULL);
155
156    map = rws->buffer_map(rbuf->buf, r300->cs,
157                          PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD | usage);
158
159    memcpy(map + box->x, data, box->width);
160
161    rws->buffer_unmap(rbuf->buf);
162}
163
164static const struct u_resource_vtbl r300_buffer_vtbl =
165{
166   NULL,                               /* get_handle */
167   r300_buffer_destroy,                /* resource_destroy */
168   r300_buffer_get_transfer,           /* get_transfer */
169   r300_buffer_transfer_destroy,       /* transfer_destroy */
170   r300_buffer_transfer_map,           /* transfer_map */
171   NULL,                               /* transfer_flush_region */
172   r300_buffer_transfer_unmap,         /* transfer_unmap */
173   r300_buffer_transfer_inline_write   /* transfer_inline_write */
174};
175
176struct pipe_resource *r300_buffer_create(struct pipe_screen *screen,
177					 const struct pipe_resource *templ)
178{
179    struct r300_screen *r300screen = r300_screen(screen);
180    struct r300_resource *rbuf;
181    unsigned alignment = 16;
182
183    rbuf = util_slab_alloc(&r300screen->pool_buffers);
184
185    rbuf->b.b.b = *templ;
186    rbuf->b.b.vtbl = &r300_buffer_vtbl;
187    pipe_reference_init(&rbuf->b.b.b.reference, 1);
188    rbuf->b.b.b.screen = screen;
189    rbuf->b.user_ptr = NULL;
190    rbuf->domain = RADEON_DOMAIN_GTT;
191    rbuf->buf = NULL;
192    rbuf->constant_buffer = NULL;
193
194    /* Alloc constant buffers in RAM. */
195    if (templ->bind & PIPE_BIND_CONSTANT_BUFFER) {
196        rbuf->constant_buffer = MALLOC(templ->width0);
197        return &rbuf->b.b.b;
198    }
199
200    rbuf->buf =
201        r300screen->rws->buffer_create(r300screen->rws,
202                                       rbuf->b.b.b.width0, alignment,
203                                       rbuf->b.b.b.bind, rbuf->domain);
204    if (!rbuf->buf) {
205        util_slab_free(&r300screen->pool_buffers, rbuf);
206        return NULL;
207    }
208
209    rbuf->cs_buf =
210        r300screen->rws->buffer_get_cs_handle(rbuf->buf);
211
212    return &rbuf->b.b.b;
213}
214
215struct pipe_resource *r300_user_buffer_create(struct pipe_screen *screen,
216					      void *ptr, unsigned size,
217					      unsigned bind)
218{
219    struct r300_screen *r300screen = r300_screen(screen);
220    struct r300_resource *rbuf;
221
222    rbuf = util_slab_alloc(&r300screen->pool_buffers);
223
224    pipe_reference_init(&rbuf->b.b.b.reference, 1);
225    rbuf->b.b.b.screen = screen;
226    rbuf->b.b.b.target = PIPE_BUFFER;
227    rbuf->b.b.b.format = PIPE_FORMAT_R8_UNORM;
228    rbuf->b.b.b.usage = PIPE_USAGE_IMMUTABLE;
229    rbuf->b.b.b.bind = bind;
230    rbuf->b.b.b.width0 = ~0;
231    rbuf->b.b.b.height0 = 1;
232    rbuf->b.b.b.depth0 = 1;
233    rbuf->b.b.b.array_size = 1;
234    rbuf->b.b.b.flags = 0;
235    rbuf->b.b.vtbl = &r300_buffer_vtbl;
236    rbuf->b.user_ptr = ptr;
237    rbuf->domain = RADEON_DOMAIN_GTT;
238    rbuf->buf = NULL;
239    rbuf->constant_buffer = NULL;
240    return &rbuf->b.b.b;
241}
242