r300_screen_buffer.c revision 80f24c1575688e9cd4a5a811137f43b7e0a661bb
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_buffer_is_user_buffer(buf))
44 	return PIPE_UNREFERENCED;
45
46    if (r300->rws->cs_is_buffer_referenced(r300->cs, rbuf->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 face, unsigned level)
55{
56    return r300_buffer_is_referenced(context, buf, R300_REF_CS);
57}
58
59/* External helper, not required to implent u_resource_vtbl:
60 */
61int r300_upload_index_buffer(struct r300_context *r300,
62			     struct pipe_resource **index_buffer,
63			     unsigned index_size,
64			     unsigned start,
65			     unsigned count,
66			     unsigned *out_offset)
67{
68   struct pipe_resource *upload_buffer = NULL;
69   unsigned index_offset = start * index_size;
70   int ret = 0;
71
72    if (r300_buffer_is_user_buffer(*index_buffer)) {
73	ret = u_upload_buffer(r300->upload_ib,
74			      index_offset,
75			      count * index_size,
76			      *index_buffer,
77			      &index_offset,
78			      &upload_buffer);
79	if (ret) {
80	    goto done;
81	}
82	*index_buffer = upload_buffer;
83	*out_offset = index_offset / index_size;
84    } else
85        *out_offset = start;
86
87 done:
88    //    if (upload_buffer)
89    //	pipe_resource_reference(&upload_buffer, NULL);
90    return ret;
91}
92
93/* External helper, not required to implement u_resource_vtbl:
94 */
95int r300_upload_user_buffers(struct r300_context *r300)
96{
97    enum pipe_error ret = PIPE_OK;
98    int i, nr;
99
100    nr = r300->velems->count;
101
102    for (i = 0; i < nr; i++) {
103        struct pipe_vertex_buffer *vb =
104            &r300->vertex_buffer[r300->velems->velem[i].vertex_buffer_index];
105
106        if (r300_buffer_is_user_buffer(vb->buffer)) {
107            struct pipe_resource *upload_buffer = NULL;
108            unsigned offset = 0; /*vb->buffer_offset * 4;*/
109            unsigned size = vb->buffer->width0;
110            unsigned upload_offset;
111            ret = u_upload_buffer(r300->upload_vb,
112                                  offset, size,
113                                  vb->buffer,
114                                  &upload_offset, &upload_buffer);
115            if (ret)
116                return ret;
117
118            pipe_resource_reference(&vb->buffer, NULL);
119            vb->buffer = upload_buffer;
120            vb->buffer_offset = upload_offset;
121        }
122    }
123    return ret;
124}
125
126static void r300_buffer_destroy(struct pipe_screen *screen,
127				struct pipe_resource *buf)
128{
129    struct r300_screen *r300screen = r300_screen(screen);
130    struct r300_buffer *rbuf = r300_buffer(buf);
131    struct r300_winsys_screen *rws = r300screen->rws;
132
133    if (rbuf->constant_buffer)
134        FREE(rbuf->constant_buffer);
135
136    if (rbuf->buf)
137        rws->buffer_reference(rws, &rbuf->buf, NULL);
138
139    util_slab_free(&r300screen->pool_buffers, rbuf);
140}
141
142static struct pipe_transfer*
143r300_default_get_transfer(struct pipe_context *context,
144                          struct pipe_resource *resource,
145                          struct pipe_subresource sr,
146                          unsigned usage,
147                          const struct pipe_box *box)
148{
149   struct r300_context *r300 = r300_context(context);
150   struct pipe_transfer *transfer =
151         util_slab_alloc(&r300->pool_transfers);
152
153   transfer->resource = resource;
154   transfer->sr = sr;
155   transfer->usage = usage;
156   transfer->box = *box;
157   transfer->stride = 0;
158   transfer->slice_stride = 0;
159   transfer->data = NULL;
160
161   /* Note strides are zero, this is ok for buffers, but not for
162    * textures 2d & higher at least.
163    */
164   return transfer;
165}
166
167static void r300_default_transfer_destroy(struct pipe_context *pipe,
168                                          struct pipe_transfer *transfer)
169{
170   struct r300_context *r300 = r300_context(pipe);
171   util_slab_free(&r300->pool_transfers, transfer);
172}
173
174static void *
175r300_buffer_transfer_map( struct pipe_context *pipe,
176			  struct pipe_transfer *transfer )
177{
178    struct r300_context *r300 = r300_context(pipe);
179    struct r300_screen *r300screen = r300_screen(pipe->screen);
180    struct r300_winsys_screen *rws = r300screen->rws;
181    struct r300_buffer *rbuf = r300_buffer(transfer->resource);
182    uint8_t *map;
183    boolean flush = FALSE;
184    unsigned i;
185
186    if (rbuf->user_buffer)
187        return (uint8_t *) rbuf->user_buffer + transfer->box.x;
188    if (rbuf->constant_buffer)
189        return (uint8_t *) rbuf->constant_buffer + transfer->box.x;
190
191    /* check if the mapping is to a range we already flushed */
192    if (transfer->usage & PIPE_TRANSFER_DISCARD) {
193	for (i = 0; i < rbuf->num_ranges; i++) {
194	    if ((transfer->box.x >= rbuf->ranges[i].start) &&
195		(transfer->box.x < rbuf->ranges[i].end))
196		flush = TRUE;
197
198	    if (flush) {
199		/* unreference this hw buffer and allocate a new one */
200		rws->buffer_reference(rws, &rbuf->buf, NULL);
201
202		rbuf->num_ranges = 0;
203                rbuf->buf =
204                    r300screen->rws->buffer_create(r300screen->rws,
205                                                   rbuf->b.b.width0, 16,
206                                                   rbuf->b.b.bind,
207                                                   rbuf->b.b.usage,
208                                                   rbuf->domain);
209		break;
210	    }
211	}
212    }
213
214    map = rws->buffer_map(rws, rbuf->buf, r300->cs, transfer->usage);
215
216    if (map == NULL)
217        return NULL;
218
219    /* map_buffer() returned a pointer to the beginning of the buffer,
220     * but transfers are expected to return a pointer to just the
221     * region specified in the box.
222     */
223    return map + transfer->box.x;
224}
225
226static void r300_buffer_transfer_flush_region( struct pipe_context *pipe,
227					       struct pipe_transfer *transfer,
228					       const struct pipe_box *box)
229{
230    struct r300_buffer *rbuf = r300_buffer(transfer->resource);
231    unsigned i;
232    unsigned offset = transfer->box.x + box->x;
233    unsigned length = box->width;
234
235    assert(box->x + box->width <= transfer->box.width);
236
237    if (rbuf->user_buffer)
238	return;
239    if (rbuf->constant_buffer)
240        return;
241
242    /* mark the range as used */
243    for(i = 0; i < rbuf->num_ranges; ++i) {
244	if(offset <= rbuf->ranges[i].end && rbuf->ranges[i].start <= (offset+box->width)) {
245	    rbuf->ranges[i].start = MIN2(rbuf->ranges[i].start, offset);
246	    rbuf->ranges[i].end   = MAX2(rbuf->ranges[i].end, (offset+length));
247	    return;
248	}
249    }
250
251    rbuf->ranges[rbuf->num_ranges].start = offset;
252    rbuf->ranges[rbuf->num_ranges].end = offset+length;
253    rbuf->num_ranges++;
254}
255
256static void r300_buffer_transfer_unmap( struct pipe_context *pipe,
257			    struct pipe_transfer *transfer )
258{
259    struct r300_screen *r300screen = r300_screen(pipe->screen);
260    struct r300_winsys_screen *rws = r300screen->rws;
261    struct r300_buffer *rbuf = r300_buffer(transfer->resource);
262
263    if (rbuf->buf) {
264        rws->buffer_unmap(rws, rbuf->buf);
265    }
266}
267
268struct u_resource_vtbl r300_buffer_vtbl =
269{
270   u_default_resource_get_handle,      /* get_handle */
271   r300_buffer_destroy,                /* resource_destroy */
272   r300_buffer_is_referenced_by_cs,    /* is_buffer_referenced */
273   r300_default_get_transfer,          /* get_transfer */
274   r300_default_transfer_destroy,      /* transfer_destroy */
275   r300_buffer_transfer_map,           /* transfer_map */
276   r300_buffer_transfer_flush_region,  /* transfer_flush_region */
277   r300_buffer_transfer_unmap,         /* transfer_unmap */
278   u_default_transfer_inline_write     /* transfer_inline_write */
279};
280
281struct pipe_resource *r300_buffer_create(struct pipe_screen *screen,
282					 const struct pipe_resource *templ)
283{
284    struct r300_screen *r300screen = r300_screen(screen);
285    struct r300_buffer *rbuf;
286    unsigned alignment = 16;
287
288    rbuf = util_slab_alloc(&r300screen->pool_buffers);
289
290    rbuf->magic = R300_BUFFER_MAGIC;
291
292    rbuf->b.b = *templ;
293    rbuf->b.vtbl = &r300_buffer_vtbl;
294    pipe_reference_init(&rbuf->b.b.reference, 1);
295    rbuf->b.b.screen = screen;
296    rbuf->domain = R300_DOMAIN_GTT;
297    rbuf->num_ranges = 0;
298    rbuf->buf = NULL;
299    rbuf->constant_buffer = NULL;
300    rbuf->user_buffer = NULL;
301
302    /* Alloc constant buffers in RAM. */
303    if (templ->bind & PIPE_BIND_CONSTANT_BUFFER) {
304        rbuf->constant_buffer = MALLOC(templ->width0);
305        return &rbuf->b.b;
306    }
307
308    rbuf->buf =
309        r300screen->rws->buffer_create(r300screen->rws,
310                                       rbuf->b.b.width0, alignment,
311                                       rbuf->b.b.bind, rbuf->b.b.usage,
312                                       rbuf->domain);
313
314    if (!rbuf->buf) {
315        util_slab_free(&r300screen->pool_buffers, rbuf);
316        return NULL;
317    }
318
319    return &rbuf->b.b;
320}
321
322struct pipe_resource *r300_user_buffer_create(struct pipe_screen *screen,
323					      void *ptr,
324					      unsigned bytes,
325					      unsigned bind)
326{
327    struct r300_screen *r300screen = r300_screen(screen);
328    struct r300_buffer *rbuf;
329
330    rbuf = util_slab_alloc(&r300screen->pool_buffers);
331
332    rbuf->magic = R300_BUFFER_MAGIC;
333
334    pipe_reference_init(&rbuf->b.b.reference, 1);
335    rbuf->b.vtbl = &r300_buffer_vtbl;
336    rbuf->b.b.screen = screen;
337    rbuf->b.b.target = PIPE_BUFFER;
338    rbuf->b.b.format = PIPE_FORMAT_R8_UNORM;
339    rbuf->b.b.usage = PIPE_USAGE_IMMUTABLE;
340    rbuf->b.b.bind = bind;
341    rbuf->b.b.width0 = bytes;
342    rbuf->b.b.height0 = 1;
343    rbuf->b.b.depth0 = 1;
344    rbuf->b.b.flags = 0;
345    rbuf->domain = R300_DOMAIN_GTT;
346    rbuf->num_ranges = 0;
347    rbuf->buf = NULL;
348    rbuf->constant_buffer = NULL;
349    rbuf->user_buffer = ptr;
350    return &rbuf->b.b;
351}
352