Squashed commit of the following:
[profile/ivi/mesa.git] / src / gallium / drivers / svga / svga_resource_buffer.c
1 /**********************************************************
2  * Copyright 2008-2009 VMware, Inc.  All rights reserved.
3  *
4  * Permission is hereby granted, free of charge, to any person
5  * obtaining a copy of this software and associated documentation
6  * files (the "Software"), to deal in the Software without
7  * restriction, including without limitation the rights to use, copy,
8  * modify, merge, publish, distribute, sublicense, and/or sell copies
9  * of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  *
24  **********************************************************/
25
26 #include "svga_cmd.h"
27
28 #include "pipe/p_state.h"
29 #include "pipe/p_defines.h"
30 #include "util/u_inlines.h"
31 #include "os/os_thread.h"
32 #include "util/u_math.h"
33 #include "util/u_memory.h"
34
35 #include "svga_context.h"
36 #include "svga_screen.h"
37 #include "svga_resource_buffer.h"
38 #include "svga_resource_buffer_upload.h"
39 #include "svga_winsys.h"
40 #include "svga_debug.h"
41
42
43 /**
44  * Vertex and index buffers need hardware backing.  Constant buffers
45  * do not.  No other types of buffers currently supported.
46  */
47 static INLINE boolean
48 svga_buffer_needs_hw_storage(unsigned usage)
49 {
50    return usage & (PIPE_BIND_VERTEX_BUFFER | PIPE_BIND_INDEX_BUFFER);
51 }
52
53
54 static unsigned int
55 svga_buffer_is_referenced( struct pipe_context *pipe,
56                              struct pipe_resource *buf,
57                              unsigned face, unsigned level)
58 {
59    struct svga_screen *ss = svga_screen(pipe->screen);
60    struct svga_buffer *sbuf = svga_buffer(buf);
61
62    /**
63     * XXX: Check this.
64     * The screen may cache buffer writes, but when we map, we map out
65     * of those cached writes, so we don't need to set a
66     * PIPE_REFERENCED_FOR_WRITE flag for cached buffers.
67     */
68
69    if (!sbuf->handle || ss->sws->surface_is_flushed(ss->sws, sbuf->handle))
70      return PIPE_UNREFERENCED;
71
72    /**
73     * sws->surface_is_flushed() does not distinguish between read references
74     * and write references. So assume a reference is both,
75     * however, we make an exception for index- and vertex buffers, to avoid
76     * a flush in st_bufferobj_get_subdata, during display list replay.
77     */
78
79    if (sbuf->b.b.bind & (PIPE_BIND_VERTEX_BUFFER | PIPE_BIND_INDEX_BUFFER))
80       return PIPE_REFERENCED_FOR_READ;
81
82    return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE;
83 }
84
85
86
87
88
89
90 static void *
91 svga_buffer_map_range( struct pipe_screen *screen,
92                        struct pipe_resource *buf,
93                        unsigned offset,
94                        unsigned length,
95                        unsigned usage )
96 {
97    struct svga_screen *ss = svga_screen(screen); 
98    struct svga_winsys_screen *sws = ss->sws;
99    struct svga_buffer *sbuf = svga_buffer( buf );
100    void *map;
101
102    if (!sbuf->swbuf && !sbuf->hwbuf) {
103       if (svga_buffer_create_hw_storage(ss, sbuf) != PIPE_OK) {
104          /*
105           * We can't create a hardware buffer big enough, so create a malloc
106           * buffer instead.
107           */
108          debug_printf("%s: failed to allocate %u KB of DMA, splitting DMA transfers\n",
109                       __FUNCTION__,
110                       (sbuf->b.b.width0 + 1023)/1024);
111
112          sbuf->swbuf = align_malloc(sbuf->b.b.width0, 16);
113       }
114    }
115
116    if (sbuf->swbuf) {
117       /* User/malloc buffer */
118       map = sbuf->swbuf;
119    }
120    else if (sbuf->hwbuf) {
121       map = sws->buffer_map(sws, sbuf->hwbuf, usage);
122    }
123    else {
124       map = NULL;
125    }
126
127    if(map) {
128       pipe_mutex_lock(ss->swc_mutex);
129
130       ++sbuf->map.count;
131
132       if (usage & PIPE_TRANSFER_WRITE) {
133          assert(sbuf->map.count <= 1);
134          sbuf->map.writing = TRUE;
135          if (usage & PIPE_TRANSFER_FLUSH_EXPLICIT)
136             sbuf->map.flush_explicit = TRUE;
137       }
138       
139       pipe_mutex_unlock(ss->swc_mutex);
140    }
141    
142    return map;
143 }
144
145
146
147 static void 
148 svga_buffer_flush_mapped_range( struct pipe_screen *screen,
149                                 struct pipe_resource *buf,
150                                 unsigned offset, unsigned length)
151 {
152    struct svga_buffer *sbuf = svga_buffer( buf );
153    struct svga_screen *ss = svga_screen(screen);
154    
155    pipe_mutex_lock(ss->swc_mutex);
156    assert(sbuf->map.writing);
157    if(sbuf->map.writing) {
158       assert(sbuf->map.flush_explicit);
159       svga_buffer_add_range(sbuf, offset, offset + length);
160    }
161    pipe_mutex_unlock(ss->swc_mutex);
162 }
163
164 static void 
165 svga_buffer_unmap( struct pipe_screen *screen,
166                    struct pipe_resource *buf)
167 {
168    struct svga_screen *ss = svga_screen(screen); 
169    struct svga_winsys_screen *sws = ss->sws;
170    struct svga_buffer *sbuf = svga_buffer( buf );
171    
172    pipe_mutex_lock(ss->swc_mutex);
173    
174    assert(sbuf->map.count);
175    if(sbuf->map.count)
176       --sbuf->map.count;
177
178    if(sbuf->hwbuf)
179       sws->buffer_unmap(sws, sbuf->hwbuf);
180
181    if(sbuf->map.writing) {
182       if(!sbuf->map.flush_explicit) {
183          /* No mapped range was flushed -- flush the whole buffer */
184          SVGA_DBG(DEBUG_DMA, "flushing the whole buffer\n");
185    
186          svga_buffer_add_range(sbuf, 0, sbuf->b.b.width0);
187       }
188       
189       sbuf->map.writing = FALSE;
190       sbuf->map.flush_explicit = FALSE;
191    }
192
193    pipe_mutex_unlock(ss->swc_mutex);
194 }
195
196
197
198 static void
199 svga_buffer_destroy( struct pipe_screen *screen,
200                      struct pipe_resource *buf )
201 {
202    struct svga_screen *ss = svga_screen(screen); 
203    struct svga_buffer *sbuf = svga_buffer( buf );
204
205    assert(!p_atomic_read(&buf->reference.count));
206    
207    assert(!sbuf->dma.pending);
208
209    if(sbuf->handle)
210       svga_buffer_destroy_host_surface(ss, sbuf);
211    
212    if(sbuf->uploaded.buffer)
213       pipe_resource_reference(&sbuf->uploaded.buffer, NULL);
214
215    if(sbuf->hwbuf)
216       svga_buffer_destroy_hw_storage(ss, sbuf);
217    
218    if(sbuf->swbuf && !sbuf->user)
219       align_free(sbuf->swbuf);
220    
221    FREE(sbuf);
222 }
223
224
225 /* Keep the original code more or less intact, implement transfers in
226  * terms of the old functions.
227  */
228 static void *
229 svga_buffer_transfer_map( struct pipe_context *pipe,
230                           struct pipe_transfer *transfer )
231 {
232    uint8_t *map = svga_buffer_map_range( pipe->screen,
233                                          transfer->resource,
234                                          transfer->box.x,
235                                          transfer->box.width,
236                                          transfer->usage );
237    if (map == NULL)
238       return NULL;
239
240    /* map_buffer() returned a pointer to the beginning of the buffer,
241     * but transfers are expected to return a pointer to just the
242     * region specified in the box.
243     */
244    return map + transfer->box.x;
245 }
246
247
248
249 static void svga_buffer_transfer_flush_region( struct pipe_context *pipe,
250                                                struct pipe_transfer *transfer,
251                                                const struct pipe_box *box)
252 {
253    assert(box->x + box->width <= transfer->box.width);
254
255    svga_buffer_flush_mapped_range(pipe->screen,
256                                   transfer->resource,
257                                   transfer->box.x + box->x,
258                                   box->width);
259 }
260
261 static void svga_buffer_transfer_unmap( struct pipe_context *pipe,
262                             struct pipe_transfer *transfer )
263 {
264    svga_buffer_unmap(pipe->screen,
265                      transfer->resource);
266 }
267
268
269
270
271
272
273
274 struct u_resource_vtbl svga_buffer_vtbl = 
275 {
276    u_default_resource_get_handle,      /* get_handle */
277    svga_buffer_destroy,              /* resource_destroy */
278    svga_buffer_is_referenced,        /* is_resource_referenced */
279    u_default_get_transfer,           /* get_transfer */
280    u_default_transfer_destroy,       /* transfer_destroy */
281    svga_buffer_transfer_map,         /* transfer_map */
282    svga_buffer_transfer_flush_region,  /* transfer_flush_region */
283    svga_buffer_transfer_unmap,       /* transfer_unmap */
284    u_default_transfer_inline_write   /* transfer_inline_write */
285 };
286
287
288
289 struct pipe_resource *
290 svga_buffer_create(struct pipe_screen *screen,
291                    const struct pipe_resource *template)
292 {
293    struct svga_screen *ss = svga_screen(screen);
294    struct svga_buffer *sbuf;
295    
296    sbuf = CALLOC_STRUCT(svga_buffer);
297    if(!sbuf)
298       goto error1;
299    
300    sbuf->b.b = *template;
301    sbuf->b.vtbl = &svga_buffer_vtbl;
302    pipe_reference_init(&sbuf->b.b.reference, 1);
303    sbuf->b.b.screen = screen;
304
305    if(svga_buffer_needs_hw_storage(template->bind)) {
306       if(svga_buffer_create_host_surface(ss, sbuf) != PIPE_OK)
307          goto error2;
308    }
309    else {
310       sbuf->swbuf = align_malloc(template->width0, 64);
311       if(!sbuf->swbuf)
312          goto error2;
313    }
314       
315    return &sbuf->b.b; 
316
317 error2:
318    FREE(sbuf);
319 error1:
320    return NULL;
321 }
322
323 struct pipe_resource *
324 svga_user_buffer_create(struct pipe_screen *screen,
325                         void *ptr,
326                         unsigned bytes,
327                         unsigned bind)
328 {
329    struct svga_buffer *sbuf;
330    
331    sbuf = CALLOC_STRUCT(svga_buffer);
332    if(!sbuf)
333       goto no_sbuf;
334       
335    pipe_reference_init(&sbuf->b.b.reference, 1);
336    sbuf->b.vtbl = &svga_buffer_vtbl;
337    sbuf->b.b.screen = screen;
338    sbuf->b.b.format = PIPE_FORMAT_R8_UNORM; /* ?? */
339    sbuf->b.b._usage = PIPE_USAGE_IMMUTABLE;
340    sbuf->b.b.bind = bind;
341    sbuf->b.b.width0 = bytes;
342    sbuf->b.b.height0 = 1;
343    sbuf->b.b.depth0 = 1;
344
345    sbuf->swbuf = ptr;
346    sbuf->user = TRUE;
347    
348    return &sbuf->b.b; 
349
350 no_sbuf:
351    return NULL;
352 }
353
354
355