r300_screen_buffer.c revision 8d0a540020f6389ca5efcd0e1fbef45a4a1f5b6a
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_is_user_buffer(buf))
44 	return PIPE_UNREFERENCED;
45
46    if (r300->rws->cs_is_buffer_referenced(r300->cs, rbuf->cs_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 level, int layer)
55{
56    return r300_buffer_is_referenced(context, buf, R300_REF_CS);
57}
58
59void r300_upload_index_buffer(struct r300_context *r300,
60			      struct pipe_resource **index_buffer,
61			      unsigned index_size, unsigned *start,
62			      unsigned count)
63{
64    unsigned index_offset;
65    uint8_t *ptr = r300_buffer(*index_buffer)->user_buffer;
66    boolean flushed;
67
68    *index_buffer = NULL;
69
70    u_upload_data(r300->upload_ib,
71                  0, count * index_size,
72                  ptr + (*start * index_size),
73                  &index_offset,
74                  index_buffer, &flushed);
75
76    *start = index_offset / index_size;
77
78    if (flushed || !r300->upload_ib_validated) {
79        r300->upload_ib_validated = FALSE;
80        r300->validate_buffers = TRUE;
81    }
82}
83
84void r300_upload_user_buffers(struct r300_context *r300,
85                              int min_index, int max_index)
86{
87    int i, nr = r300->velems->count;
88    unsigned count = max_index + 1 - min_index;
89    boolean flushed;
90    boolean uploaded[32] = {0};
91
92    for (i = 0; i < nr; i++) {
93        unsigned index = r300->velems->velem[i].vertex_buffer_index;
94        struct pipe_vertex_buffer *vb = &r300->vertex_buffer[index];
95        struct r300_buffer *userbuf = r300_buffer(vb->buffer);
96
97        if (userbuf && userbuf->user_buffer && !uploaded[index]) {
98            unsigned first, size;
99
100            if (vb->stride) {
101                first = vb->stride * min_index;
102                size = vb->stride * count;
103            } else {
104                first = 0;
105                size = r300->velems->hw_format_size[i];
106            }
107
108            u_upload_data(r300->upload_vb, first, size,
109                          userbuf->user_buffer + first,
110                          &vb->buffer_offset,
111                          &r300->real_vertex_buffer[index],
112                          &flushed);
113
114            vb->buffer_offset -= first;
115
116            r300->vertex_arrays_dirty = TRUE;
117
118            if (flushed || !r300->upload_vb_validated) {
119                r300->upload_vb_validated = FALSE;
120                r300->validate_buffers = TRUE;
121            }
122            uploaded[index] = TRUE;
123        } else {
124            assert(r300->real_vertex_buffer[index]);
125        }
126    }
127}
128
129static void r300_buffer_destroy(struct pipe_screen *screen,
130				struct pipe_resource *buf)
131{
132    struct r300_screen *r300screen = r300_screen(screen);
133    struct r300_buffer *rbuf = r300_buffer(buf);
134    struct r300_winsys_screen *rws = r300screen->rws;
135
136    if (rbuf->constant_buffer)
137        FREE(rbuf->constant_buffer);
138
139    if (rbuf->buf)
140        rws->buffer_reference(rws, &rbuf->buf, NULL);
141
142    util_slab_free(&r300screen->pool_buffers, rbuf);
143}
144
145static struct pipe_transfer*
146r300_buffer_get_transfer(struct pipe_context *context,
147                         struct pipe_resource *resource,
148                         unsigned level,
149                         unsigned usage,
150                         const struct pipe_box *box)
151{
152   struct r300_context *r300 = r300_context(context);
153   struct pipe_transfer *transfer =
154         util_slab_alloc(&r300->pool_transfers);
155
156   transfer->resource = resource;
157   transfer->level = level;
158   transfer->usage = usage;
159   transfer->box = *box;
160   transfer->stride = 0;
161   transfer->layer_stride = 0;
162   transfer->data = NULL;
163
164   /* Note strides are zero, this is ok for buffers, but not for
165    * textures 2d & higher at least.
166    */
167   return transfer;
168}
169
170static void r300_buffer_transfer_destroy(struct pipe_context *pipe,
171                                         struct pipe_transfer *transfer)
172{
173   struct r300_context *r300 = r300_context(pipe);
174   util_slab_free(&r300->pool_transfers, transfer);
175}
176
177static void *
178r300_buffer_transfer_map( struct pipe_context *pipe,
179			  struct pipe_transfer *transfer )
180{
181    struct r300_context *r300 = r300_context(pipe);
182    struct r300_screen *r300screen = r300_screen(pipe->screen);
183    struct r300_winsys_screen *rws = r300screen->rws;
184    struct r300_buffer *rbuf = r300_buffer(transfer->resource);
185    uint8_t *map;
186
187    if (rbuf->user_buffer)
188        return (uint8_t *) rbuf->user_buffer + transfer->box.x;
189    if (rbuf->constant_buffer)
190        return (uint8_t *) rbuf->constant_buffer + transfer->box.x;
191
192    map = rws->buffer_map(rws, rbuf->buf, r300->cs, transfer->usage);
193
194    if (map == NULL)
195        return NULL;
196
197    return map + transfer->box.x;
198}
199
200static void r300_buffer_transfer_flush_region( struct pipe_context *pipe,
201					       struct pipe_transfer *transfer,
202					       const struct pipe_box *box)
203{
204    /* no-op */
205}
206
207static void r300_buffer_transfer_unmap( struct pipe_context *pipe,
208			    struct pipe_transfer *transfer )
209{
210    struct r300_screen *r300screen = r300_screen(pipe->screen);
211    struct r300_winsys_screen *rws = r300screen->rws;
212    struct r300_buffer *rbuf = r300_buffer(transfer->resource);
213
214    if (rbuf->buf) {
215        rws->buffer_unmap(rws, rbuf->buf);
216    }
217}
218
219static void r300_buffer_transfer_inline_write(struct pipe_context *pipe,
220                                              struct pipe_resource *resource,
221                                              unsigned level,
222                                              unsigned usage,
223                                              const struct pipe_box *box,
224                                              const void *data,
225                                              unsigned stride,
226                                              unsigned layer_stride)
227{
228    struct r300_context *r300 = r300_context(pipe);
229    struct r300_winsys_screen *rws = r300->screen->rws;
230    struct r300_buffer *rbuf = r300_buffer(resource);
231    uint8_t *map = NULL;
232
233    if (rbuf->constant_buffer) {
234        memcpy(rbuf->constant_buffer + box->x, data, box->width);
235        return;
236    }
237    assert(rbuf->user_buffer == NULL);
238
239    map = rws->buffer_map(rws, rbuf->buf, r300->cs,
240                          PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD | usage);
241
242    memcpy(map + box->x, data, box->width);
243
244    rws->buffer_unmap(rws, rbuf->buf);
245}
246
247struct u_resource_vtbl r300_buffer_vtbl =
248{
249   u_default_resource_get_handle,      /* get_handle */
250   r300_buffer_destroy,                /* resource_destroy */
251   r300_buffer_is_referenced_by_cs,    /* is_buffer_referenced */
252   r300_buffer_get_transfer,           /* get_transfer */
253   r300_buffer_transfer_destroy,       /* transfer_destroy */
254   r300_buffer_transfer_map,           /* transfer_map */
255   r300_buffer_transfer_flush_region,  /* transfer_flush_region */
256   r300_buffer_transfer_unmap,         /* transfer_unmap */
257   r300_buffer_transfer_inline_write   /* transfer_inline_write */
258};
259
260struct pipe_resource *r300_buffer_create(struct pipe_screen *screen,
261					 const struct pipe_resource *templ)
262{
263    struct r300_screen *r300screen = r300_screen(screen);
264    struct r300_buffer *rbuf;
265    unsigned alignment = 16;
266
267    rbuf = util_slab_alloc(&r300screen->pool_buffers);
268
269    rbuf->magic = R300_BUFFER_MAGIC;
270
271    rbuf->b.b = *templ;
272    rbuf->b.vtbl = &r300_buffer_vtbl;
273    pipe_reference_init(&rbuf->b.b.reference, 1);
274    rbuf->b.b.screen = screen;
275    rbuf->domain = R300_DOMAIN_GTT;
276    rbuf->buf = NULL;
277    rbuf->constant_buffer = NULL;
278    rbuf->user_buffer = NULL;
279
280    /* Alloc constant buffers in RAM. */
281    if (templ->bind & PIPE_BIND_CONSTANT_BUFFER) {
282        rbuf->constant_buffer = MALLOC(templ->width0);
283        return &rbuf->b.b;
284    }
285
286    rbuf->buf =
287        r300screen->rws->buffer_create(r300screen->rws,
288                                       rbuf->b.b.width0, alignment,
289                                       rbuf->b.b.bind, rbuf->b.b.usage,
290                                       rbuf->domain);
291    rbuf->cs_buf =
292        r300screen->rws->buffer_get_cs_handle(r300screen->rws, rbuf->buf);
293
294    if (!rbuf->buf) {
295        util_slab_free(&r300screen->pool_buffers, rbuf);
296        return NULL;
297    }
298
299    return &rbuf->b.b;
300}
301
302struct pipe_resource *r300_user_buffer_create(struct pipe_screen *screen,
303					      void *ptr, unsigned size,
304					      unsigned bind)
305{
306    struct r300_screen *r300screen = r300_screen(screen);
307    struct r300_buffer *rbuf;
308
309    rbuf = util_slab_alloc(&r300screen->pool_buffers);
310
311    rbuf->magic = R300_BUFFER_MAGIC;
312
313    pipe_reference_init(&rbuf->b.b.reference, 1);
314    rbuf->b.vtbl = &r300_buffer_vtbl;
315    rbuf->b.b.screen = screen;
316    rbuf->b.b.target = PIPE_BUFFER;
317    rbuf->b.b.format = PIPE_FORMAT_R8_UNORM;
318    rbuf->b.b.usage = PIPE_USAGE_IMMUTABLE;
319    rbuf->b.b.bind = bind;
320    rbuf->b.b.width0 = ~0;
321    rbuf->b.b.height0 = 1;
322    rbuf->b.b.depth0 = 1;
323    rbuf->b.b.array_size = 1;
324    rbuf->b.b.flags = 0;
325    rbuf->domain = R300_DOMAIN_GTT;
326    rbuf->buf = NULL;
327    rbuf->constant_buffer = NULL;
328    rbuf->user_buffer = ptr;
329    return &rbuf->b.b;
330}
331