Squashed commit of the following:
[profile/ivi/mesa.git] / src / gallium / drivers / r300 / r300_screen_buffer.c
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
37 static 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  */
55 int 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  */
85 int 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
114 static struct r300_winsys_buffer *
115 r300_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
127 static 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
139 static 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
149 static void *
150 r300_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     }
191 just_map:
192     map = rws->buffer_map(rws, rbuf->buf, usage);
193    
194     return map;
195 }
196
197 static void 
198 r300_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
227 static void
228 r300_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  */
249 static void *
250 r300_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
270 static 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
282 static 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
292 struct 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
308 struct pipe_resource *r300_buffer_create(struct pipe_screen *screen,
309                                          const struct pipe_resource *template)
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 = *template;
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;
338 error2:
339     FREE(rbuf);
340 error1:
341     return NULL;
342 }
343
344
345 struct 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
371 no_rbuf:
372     return NULL;
373 }
374