r300_screen_buffer.c revision 7a1b5c937fa32968a04a11649e456a1ef8c5b442
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_format.h"
30#include "util/u_memory.h"
31#include "util/u_upload_mgr.h"
32#include "util/u_math.h"
33
34#include "r300_screen_buffer.h"
35#include "r300_winsys.h"
36
37static unsigned r300_buffer_is_referenced(struct pipe_context *context,
38					 struct pipe_resource *buf,
39					 unsigned face, unsigned level)
40{
41    struct r300_context *r300 = r300_context(context);
42    struct r300_buffer *rbuf = r300_buffer(buf);
43
44    if (r300_buffer_is_user_buffer(buf))
45 	return PIPE_UNREFERENCED;
46
47    if (r300->rws->is_buffer_referenced(r300->rws, rbuf->buf, R300_REF_CS))
48        return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE;
49
50    return PIPE_UNREFERENCED;
51}
52
53/* External helper, not required to implent u_resource_vtbl:
54 */
55int r300_upload_index_buffer(struct r300_context *r300,
56			     struct pipe_resource **index_buffer,
57			     unsigned index_size,
58			     unsigned start,
59			     unsigned count)
60{
61   struct pipe_resource *upload_buffer = NULL;
62   unsigned index_offset = start * index_size;
63   int ret = 0;
64
65    if (r300_buffer_is_user_buffer(*index_buffer)) {
66	ret = u_upload_buffer(r300->upload_ib,
67			      index_offset,
68			      count * index_size,
69			      *index_buffer,
70			      &index_offset,
71			      &upload_buffer);
72	if (ret) {
73	    goto done;
74	}
75	*index_buffer = upload_buffer;
76    }
77 done:
78    //    if (upload_buffer)
79    //	pipe_resource_reference(&upload_buffer, NULL);
80    return ret;
81}
82
83/* External helper, not required to implement u_resource_vtbl:
84 */
85int r300_upload_user_buffers(struct r300_context *r300)
86{
87    enum pipe_error ret = PIPE_OK;
88    int i, nr;
89
90    nr = r300->vertex_buffer_count;
91
92    for (i = 0; i < nr; i++) {
93	if (r300_buffer_is_user_buffer(r300->vertex_buffer[i].buffer)) {
94	    struct pipe_resource *upload_buffer = NULL;
95	    unsigned offset = 0; /*r300->vertex_buffer[i].buffer_offset * 4;*/
96	    unsigned size = r300->vertex_buffer[i].buffer->width0;
97	    unsigned upload_offset;
98	    ret = u_upload_buffer(r300->upload_vb,
99				  offset, size,
100				  r300->vertex_buffer[i].buffer,
101				  &upload_offset, &upload_buffer);
102	    if (ret)
103		return ret;
104
105	    pipe_resource_reference(&r300->vertex_buffer[i].buffer, NULL);
106	    r300->vertex_buffer[i].buffer = upload_buffer;
107	    r300->vertex_buffer[i].buffer_offset = upload_offset;
108	}
109    }
110    return ret;
111}
112
113static struct r300_winsys_buffer *
114r300_winsys_buffer_create(struct r300_screen *r300screen,
115			  unsigned alignment,
116			  unsigned usage,
117			  unsigned size)
118{
119    struct r300_winsys_screen *rws = r300screen->rws;
120    struct r300_winsys_buffer *buf;
121
122    buf = rws->buffer_create(rws, alignment, usage, size);
123    return buf;
124}
125
126static void r300_winsys_buffer_destroy(struct r300_screen *r300screen,
127				       struct r300_buffer *rbuf)
128{
129    struct r300_winsys_screen *rws = r300screen->rws;
130
131    if (rbuf->buf) {
132	rws->buffer_reference(rws, &rbuf->buf, NULL);
133	rbuf->buf = NULL;
134    }
135}
136
137static void r300_buffer_destroy(struct pipe_screen *screen,
138				struct pipe_resource *buf)
139{
140    struct r300_screen *r300screen = r300_screen(screen);
141    struct r300_buffer *rbuf = r300_buffer(buf);
142
143    r300_winsys_buffer_destroy(r300screen, rbuf);
144    FREE(rbuf);
145}
146
147static void *
148r300_buffer_transfer_map( struct pipe_context *pipe,
149			  struct pipe_transfer *transfer )
150{
151    struct r300_screen *r300screen = r300_screen(pipe->screen);
152    struct r300_winsys_screen *rws = r300screen->rws;
153    struct r300_buffer *rbuf = r300_buffer(transfer->resource);
154    uint8_t *map;
155    boolean flush = FALSE;
156    unsigned i;
157
158    if (rbuf->user_buffer)
159        return (uint8_t *) rbuf->user_buffer + transfer->box.x;
160
161    if (rbuf->b.b.bind & PIPE_BIND_CONSTANT_BUFFER) {
162	goto just_map;
163    }
164
165    /* check if the mapping is to a range we already flushed */
166    if (transfer->usage & PIPE_TRANSFER_DISCARD) {
167	for (i = 0; i < rbuf->num_ranges; i++) {
168	    if ((transfer->box.x >= rbuf->ranges[i].start) &&
169		(transfer->box.x < rbuf->ranges[i].end))
170		flush = TRUE;
171
172	    if (flush) {
173		/* unreference this hw buffer and allocate a new one */
174		rws->buffer_reference(rws, &rbuf->buf, NULL);
175
176		rbuf->num_ranges = 0;
177		rbuf->map = NULL;
178		rbuf->buf = r300_winsys_buffer_create(r300screen,
179						      16,
180						      rbuf->b.b.bind, /* XXX */
181						      rbuf->b.b.width0);
182		break;
183	    }
184	}
185    }
186just_map:
187    map = rws->buffer_map(rws, rbuf->buf, transfer->usage);
188
189    if (map == NULL)
190        return NULL;
191
192    /* map_buffer() returned a pointer to the beginning of the buffer,
193     * but transfers are expected to return a pointer to just the
194     * region specified in the box.
195     */
196    return map + transfer->box.x;
197}
198
199static void r300_buffer_transfer_flush_region( struct pipe_context *pipe,
200					       struct pipe_transfer *transfer,
201					       const struct pipe_box *box)
202{
203    struct r300_buffer *rbuf = r300_buffer(transfer->resource);
204    unsigned i;
205    unsigned offset = transfer->box.x + box->x;
206    unsigned length = box->width;
207
208    assert(box->x + box->width <= transfer->box.width);
209
210    if (rbuf->user_buffer)
211	return;
212
213    if (rbuf->b.b.bind & PIPE_BIND_CONSTANT_BUFFER)
214	return;
215
216    /* mark the range as used */
217    for(i = 0; i < rbuf->num_ranges; ++i) {
218	if(offset <= rbuf->ranges[i].end && rbuf->ranges[i].start <= (offset+box->width)) {
219	    rbuf->ranges[i].start = MIN2(rbuf->ranges[i].start, offset);
220	    rbuf->ranges[i].end   = MAX2(rbuf->ranges[i].end, (offset+length));
221	    return;
222	}
223    }
224
225    rbuf->ranges[rbuf->num_ranges].start = offset;
226    rbuf->ranges[rbuf->num_ranges].end = offset+length;
227    rbuf->num_ranges++;
228}
229
230static void r300_buffer_transfer_unmap( struct pipe_context *pipe,
231			    struct pipe_transfer *transfer )
232{
233    struct r300_screen *r300screen = r300_screen(pipe->screen);
234    struct r300_winsys_screen *rws = r300screen->rws;
235    struct r300_buffer *rbuf = r300_buffer(transfer->resource);
236
237    if (rbuf->buf) {
238        rws->buffer_unmap(rws, rbuf->buf);
239    }
240}
241
242struct u_resource_vtbl r300_buffer_vtbl =
243{
244   u_default_resource_get_handle,      /* get_handle */
245   r300_buffer_destroy,		     /* resource_destroy */
246   r300_buffer_is_referenced,	     /* is_buffer_referenced */
247   u_default_get_transfer,	     /* get_transfer */
248   u_default_transfer_destroy,	     /* transfer_destroy */
249   r300_buffer_transfer_map,	     /* transfer_map */
250   r300_buffer_transfer_flush_region,  /* transfer_flush_region */
251   r300_buffer_transfer_unmap,	     /* transfer_unmap */
252   u_default_transfer_inline_write   /* transfer_inline_write */
253};
254
255struct pipe_resource *r300_buffer_create(struct pipe_screen *screen,
256					 const struct pipe_resource *templ)
257{
258    struct r300_screen *r300screen = r300_screen(screen);
259    struct r300_buffer *rbuf;
260    unsigned alignment = 16;
261
262    rbuf = CALLOC_STRUCT(r300_buffer);
263    if (!rbuf)
264	goto error1;
265
266    rbuf->magic = R300_BUFFER_MAGIC;
267
268    rbuf->b.b = *templ;
269    rbuf->b.vtbl = &r300_buffer_vtbl;
270    pipe_reference_init(&rbuf->b.b.reference, 1);
271    rbuf->b.b.screen = screen;
272
273    if (rbuf->b.b.bind & R300_BIND_OQBO)
274        alignment = 4096;
275
276    rbuf->buf = r300_winsys_buffer_create(r300screen,
277					  alignment,
278					  rbuf->b.b.bind,
279					  rbuf->b.b.width0);
280
281    if (!rbuf->buf)
282	goto error2;
283
284    return &rbuf->b.b;
285error2:
286    FREE(rbuf);
287error1:
288    return NULL;
289}
290
291struct pipe_resource *r300_user_buffer_create(struct pipe_screen *screen,
292					      void *ptr,
293					      unsigned bytes,
294					      unsigned bind)
295{
296    struct r300_buffer *rbuf;
297
298    rbuf = CALLOC_STRUCT(r300_buffer);
299    if (!rbuf)
300	goto no_rbuf;
301
302    rbuf->magic = R300_BUFFER_MAGIC;
303
304    pipe_reference_init(&rbuf->b.b.reference, 1);
305    rbuf->b.vtbl = &r300_buffer_vtbl;
306    rbuf->b.b.screen = screen;
307    rbuf->b.b.format = PIPE_FORMAT_R8_UNORM;
308    rbuf->b.b._usage = PIPE_USAGE_IMMUTABLE;
309    rbuf->b.b.bind = bind;
310    rbuf->b.b.width0 = bytes;
311    rbuf->b.b.height0 = 1;
312    rbuf->b.b.depth0 = 1;
313
314    rbuf->user_buffer = ptr;
315    return &rbuf->b.b;
316
317no_rbuf:
318    return NULL;
319}
320