r300_screen_buffer.c revision bb4f5fff0c782f35353e8bfc1b1227e3cc3d5986
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#include <stdio.h>
26
27#include "util/u_inlines.h"
28#include "util/u_format.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
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))
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 implent 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
94	if (r300_buffer_is_user_buffer(r300->vertex_buffer[i].buffer)) {
95	    struct pipe_resource *upload_buffer = NULL;
96	    unsigned offset = 0; /*r300->vertex_buffer[i].buffer_offset * 4;*/
97	    unsigned size = r300->vertex_buffer[i].buffer->width0;
98	    unsigned upload_offset;
99	    ret = u_upload_buffer(r300->upload_vb,
100				  offset, size,
101				  r300->vertex_buffer[i].buffer,
102				  &upload_offset, &upload_buffer);
103	    if (ret)
104		return ret;
105
106	    pipe_resource_reference(&r300->vertex_buffer[i].buffer, NULL);
107	    r300->vertex_buffer[i].buffer = upload_buffer;
108	    r300->vertex_buffer[i].buffer_offset = upload_offset;
109	}
110    }
111    return ret;
112}
113
114static struct r300_winsys_buffer *
115r300_winsys_buffer_create(struct r300_screen *r300screen,
116			  unsigned alignment,
117			  unsigned usage,
118			  unsigned size)
119{
120    struct r300_winsys_screen *rws = r300screen->rws;
121    struct r300_winsys_buffer *buf;
122
123    buf = rws->buffer_create(rws, alignment, usage, size);
124    return buf;
125}
126
127static void r300_winsys_buffer_destroy(struct r300_screen *r300screen,
128				       struct r300_buffer *rbuf)
129{
130    struct r300_winsys_screen *rws = r300screen->rws;
131
132    if (rbuf->buf) {
133	rws->buffer_reference(rws, &rbuf->buf, NULL);
134	rbuf->buf = NULL;
135    }
136}
137
138
139static void r300_buffer_destroy(struct pipe_screen *screen,
140				struct pipe_resource *buf)
141{
142    struct r300_screen *r300screen = r300_screen(screen);
143    struct r300_buffer *rbuf = r300_buffer(buf);
144
145    r300_winsys_buffer_destroy(r300screen, rbuf);
146    FREE(rbuf);
147}
148
149static void *
150r300_buffer_map_range(struct pipe_screen *screen,
151		      struct pipe_resource *buf,
152		      unsigned offset, unsigned length,
153		      unsigned usage )
154{
155    struct r300_screen *r300screen = r300_screen(screen);
156    struct r300_winsys_screen *rws = r300screen->rws;
157    struct r300_buffer *rbuf = r300_buffer(buf);
158    void *map;
159    int flush = 0;
160    int i;
161
162    if (rbuf->user_buffer)
163	return rbuf->user_buffer;
164
165    if (rbuf->b.b.bind & PIPE_BIND_CONSTANT_BUFFER) {
166	goto just_map;
167    }
168
169    /* check if the mapping is to a range we already flushed */
170    if (usage & PIPE_TRANSFER_DISCARD) {
171	for (i = 0; i < rbuf->num_ranges; i++) {
172
173	    if ((offset >= rbuf->ranges[i].start) &&
174		(offset < rbuf->ranges[i].end))
175		flush = 1;
176
177	    if (flush) {
178		/* unreference this hw buffer and allocate a new one */
179		rws->buffer_reference(rws, &rbuf->buf, NULL);
180
181		rbuf->num_ranges = 0;
182		rbuf->map = NULL;
183		rbuf->buf = r300_winsys_buffer_create(r300screen,
184						      16,
185						      rbuf->b.b.bind, /* XXX */
186						      rbuf->b.b.width0);
187		break;
188	    }
189	}
190    }
191just_map:
192    map = rws->buffer_map(rws, rbuf->buf, usage);
193
194    return map;
195}
196
197static void
198r300_buffer_flush_mapped_range( struct pipe_screen *screen,
199				struct pipe_resource *buf,
200				unsigned offset,
201				unsigned length )
202{
203    struct r300_buffer *rbuf = r300_buffer(buf);
204    int i;
205
206    if (rbuf->user_buffer)
207	return;
208
209    if (rbuf->b.b.bind & PIPE_BIND_CONSTANT_BUFFER)
210	return;
211
212    /* mark the range as used */
213    for(i = 0; i < rbuf->num_ranges; ++i) {
214	if(offset <= rbuf->ranges[i].end && rbuf->ranges[i].start <= (offset+length)) {
215	    rbuf->ranges[i].start = MIN2(rbuf->ranges[i].start, offset);
216	    rbuf->ranges[i].end   = MAX2(rbuf->ranges[i].end, (offset+length));
217	    return;
218	}
219    }
220
221    rbuf->ranges[rbuf->num_ranges].start = offset;
222    rbuf->ranges[rbuf->num_ranges].end = offset+length;
223    rbuf->num_ranges++;
224}
225
226
227static void
228r300_buffer_unmap(struct pipe_screen *screen,
229		  struct pipe_resource *buf)
230{
231    struct r300_screen *r300screen = r300_screen(screen);
232    struct r300_winsys_screen *rws = r300screen->rws;
233    struct r300_buffer *rbuf = r300_buffer(buf);
234
235    if (rbuf->buf) {
236        rws->buffer_unmap(rws, rbuf->buf);
237    }
238}
239
240
241
242
243/* As a first step, keep the original code intact, implement buffer
244 * transfers in terms of the old map/unmap functions.
245 *
246 * Utility functions for transfer create/destroy are hooked in and
247 * just record the arguments to those functions.
248 */
249static void *
250r300_buffer_transfer_map( struct pipe_context *pipe,
251			  struct pipe_transfer *transfer )
252{
253   uint8_t *map = r300_buffer_map_range( pipe->screen,
254					 transfer->resource,
255					 transfer->box.x,
256					 transfer->box.width,
257					 transfer->usage );
258   if (map == NULL)
259      return NULL;
260
261   /* map_buffer() returned a pointer to the beginning of the buffer,
262    * but transfers are expected to return a pointer to just the
263    * region specified in the box.
264    */
265   return map + transfer->box.x;
266}
267
268
269
270static void r300_buffer_transfer_flush_region( struct pipe_context *pipe,
271					       struct pipe_transfer *transfer,
272					       const struct pipe_box *box)
273{
274   assert(box->x + box->width <= transfer->box.width);
275
276   r300_buffer_flush_mapped_range(pipe->screen,
277				  transfer->resource,
278				  transfer->box.x + box->x,
279				  box->width);
280}
281
282static void r300_buffer_transfer_unmap( struct pipe_context *pipe,
283			    struct pipe_transfer *transfer )
284{
285   r300_buffer_unmap(pipe->screen,
286		     transfer->resource);
287}
288
289
290
291
292struct u_resource_vtbl r300_buffer_vtbl =
293{
294   u_default_resource_get_handle,      /* get_handle */
295   r300_buffer_destroy,		     /* resource_destroy */
296   r300_buffer_is_referenced,	     /* is_buffer_referenced */
297   u_default_get_transfer,	     /* get_transfer */
298   u_default_transfer_destroy,	     /* transfer_destroy */
299   r300_buffer_transfer_map,	     /* transfer_map */
300   r300_buffer_transfer_flush_region,  /* transfer_flush_region */
301   r300_buffer_transfer_unmap,	     /* transfer_unmap */
302   u_default_transfer_inline_write   /* transfer_inline_write */
303};
304
305
306
307
308struct pipe_resource *r300_buffer_create(struct pipe_screen *screen,
309					 const struct pipe_resource *templ)
310{
311    struct r300_screen *r300screen = r300_screen(screen);
312    struct r300_buffer *rbuf;
313    unsigned alignment = 16;
314
315    rbuf = CALLOC_STRUCT(r300_buffer);
316    if (!rbuf)
317	goto error1;
318
319    rbuf->magic = R300_BUFFER_MAGIC;
320
321    rbuf->b.b = *templ;
322    rbuf->b.vtbl = &r300_buffer_vtbl;
323    pipe_reference_init(&rbuf->b.b.reference, 1);
324    rbuf->b.b.screen = screen;
325
326    if (rbuf->b.b.bind & R300_BIND_OQBO)
327       alignment = 4096;
328
329    rbuf->buf = r300_winsys_buffer_create(r300screen,
330					  alignment,
331					  rbuf->b.b.bind,
332					  rbuf->b.b.width0);
333
334    if (!rbuf->buf)
335	goto error2;
336
337    return &rbuf->b.b;
338error2:
339    FREE(rbuf);
340error1:
341    return NULL;
342}
343
344
345struct pipe_resource *r300_user_buffer_create(struct pipe_screen *screen,
346					      void *ptr,
347					      unsigned bytes,
348					      unsigned bind)
349{
350    struct r300_buffer *rbuf;
351
352    rbuf = CALLOC_STRUCT(r300_buffer);
353    if (!rbuf)
354	goto no_rbuf;
355
356    rbuf->magic = R300_BUFFER_MAGIC;
357
358    pipe_reference_init(&rbuf->b.b.reference, 1);
359    rbuf->b.vtbl = &r300_buffer_vtbl;
360    rbuf->b.b.screen = screen;
361    rbuf->b.b.format = PIPE_FORMAT_R8_UNORM;
362    rbuf->b.b._usage = PIPE_USAGE_IMMUTABLE;
363    rbuf->b.b.bind = bind;
364    rbuf->b.b.width0 = bytes;
365    rbuf->b.b.height0 = 1;
366    rbuf->b.b.depth0 = 1;
367
368    rbuf->user_buffer = ptr;
369    return &rbuf->b.b;
370
371no_rbuf:
372    return NULL;
373}
374
375