svga: Make sure that refcnt debugger gets the correct backtrace for create
[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 level, int layer)
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 if (0) {
109 debug_printf("%s: failed to allocate %u KB of DMA, "
110 "splitting DMA transfers\n",
111 __FUNCTION__,
112 (sbuf->b.b.width0 + 1023)/1024);
113 }
114
115 sbuf->swbuf = align_malloc(sbuf->b.b.width0, 16);
116 }
117 }
118
119 if (sbuf->swbuf) {
120 /* User/malloc buffer */
121 map = sbuf->swbuf;
122 }
123 else if (sbuf->hwbuf) {
124 map = sws->buffer_map(sws, sbuf->hwbuf, usage);
125 }
126 else {
127 map = NULL;
128 }
129
130 if(map) {
131 ++sbuf->map.count;
132
133 if (usage & PIPE_TRANSFER_WRITE) {
134 assert(sbuf->map.count <= 1);
135 sbuf->map.writing = TRUE;
136 if (usage & PIPE_TRANSFER_FLUSH_EXPLICIT)
137 sbuf->map.flush_explicit = TRUE;
138 }
139 }
140
141 return map;
142 }
143
144
145
146 static void
147 svga_buffer_flush_mapped_range( struct pipe_screen *screen,
148 struct pipe_resource *buf,
149 unsigned offset, unsigned length)
150 {
151 struct svga_buffer *sbuf = svga_buffer( buf );
152 struct svga_screen *ss = svga_screen(screen);
153
154 pipe_mutex_lock(ss->swc_mutex);
155 assert(sbuf->map.writing);
156 if(sbuf->map.writing) {
157 assert(sbuf->map.flush_explicit);
158 svga_buffer_add_range(sbuf, offset, offset + length);
159 }
160 pipe_mutex_unlock(ss->swc_mutex);
161 }
162
163 static void
164 svga_buffer_unmap( struct pipe_screen *screen,
165 struct pipe_resource *buf)
166 {
167 struct svga_screen *ss = svga_screen(screen);
168 struct svga_winsys_screen *sws = ss->sws;
169 struct svga_buffer *sbuf = svga_buffer( buf );
170
171 pipe_mutex_lock(ss->swc_mutex);
172
173 assert(sbuf->map.count);
174 if(sbuf->map.count)
175 --sbuf->map.count;
176
177 if(sbuf->hwbuf)
178 sws->buffer_unmap(sws, sbuf->hwbuf);
179
180 if(sbuf->map.writing) {
181 if(!sbuf->map.flush_explicit) {
182 /* No mapped range was flushed -- flush the whole buffer */
183 SVGA_DBG(DEBUG_DMA, "flushing the whole buffer\n");
184
185 svga_buffer_add_range(sbuf, 0, sbuf->b.b.width0);
186 }
187
188 sbuf->map.writing = FALSE;
189 sbuf->map.flush_explicit = FALSE;
190 }
191
192 pipe_mutex_unlock(ss->swc_mutex);
193 }
194
195
196
197 static void
198 svga_buffer_destroy( struct pipe_screen *screen,
199 struct pipe_resource *buf )
200 {
201 struct svga_screen *ss = svga_screen(screen);
202 struct svga_buffer *sbuf = svga_buffer( buf );
203
204 assert(!p_atomic_read(&buf->reference.count));
205
206 assert(!sbuf->dma.pending);
207
208 if(sbuf->handle)
209 svga_buffer_destroy_host_surface(ss, sbuf);
210
211 if(sbuf->uploaded.buffer)
212 pipe_resource_reference(&sbuf->uploaded.buffer, NULL);
213
214 if(sbuf->hwbuf)
215 svga_buffer_destroy_hw_storage(ss, sbuf);
216
217 if(sbuf->swbuf && !sbuf->user)
218 align_free(sbuf->swbuf);
219
220 FREE(sbuf);
221 }
222
223
224 /* Keep the original code more or less intact, implement transfers in
225 * terms of the old functions.
226 */
227 static void *
228 svga_buffer_transfer_map( struct pipe_context *pipe,
229 struct pipe_transfer *transfer )
230 {
231 uint8_t *map = svga_buffer_map_range( pipe->screen,
232 transfer->resource,
233 transfer->box.x,
234 transfer->box.width,
235 transfer->usage );
236 if (map == NULL)
237 return NULL;
238
239 /* map_buffer() returned a pointer to the beginning of the buffer,
240 * but transfers are expected to return a pointer to just the
241 * region specified in the box.
242 */
243 return map + transfer->box.x;
244 }
245
246
247
248 static void svga_buffer_transfer_flush_region( struct pipe_context *pipe,
249 struct pipe_transfer *transfer,
250 const struct pipe_box *box)
251 {
252 assert(box->x + box->width <= transfer->box.width);
253
254 svga_buffer_flush_mapped_range(pipe->screen,
255 transfer->resource,
256 transfer->box.x + box->x,
257 box->width);
258 }
259
260 static void svga_buffer_transfer_unmap( struct pipe_context *pipe,
261 struct pipe_transfer *transfer )
262 {
263 svga_buffer_unmap(pipe->screen,
264 transfer->resource);
265 }
266
267
268
269
270
271
272
273 struct u_resource_vtbl svga_buffer_vtbl =
274 {
275 u_default_resource_get_handle, /* get_handle */
276 svga_buffer_destroy, /* resource_destroy */
277 svga_buffer_is_referenced, /* is_resource_referenced */
278 u_default_get_transfer, /* get_transfer */
279 u_default_transfer_destroy, /* transfer_destroy */
280 svga_buffer_transfer_map, /* transfer_map */
281 svga_buffer_transfer_flush_region, /* transfer_flush_region */
282 svga_buffer_transfer_unmap, /* transfer_unmap */
283 u_default_transfer_inline_write /* transfer_inline_write */
284 };
285
286
287
288 struct pipe_resource *
289 svga_buffer_create(struct pipe_screen *screen,
290 const struct pipe_resource *template)
291 {
292 struct svga_screen *ss = svga_screen(screen);
293 struct svga_buffer *sbuf;
294
295 sbuf = CALLOC_STRUCT(svga_buffer);
296 if(!sbuf)
297 goto error1;
298
299 sbuf->b.b = *template;
300 sbuf->b.vtbl = &svga_buffer_vtbl;
301 pipe_reference_init(&sbuf->b.b.reference, 1);
302 sbuf->b.b.screen = screen;
303
304 if(svga_buffer_needs_hw_storage(template->bind)) {
305 if(svga_buffer_create_host_surface(ss, sbuf) != PIPE_OK)
306 goto error2;
307 }
308 else {
309 sbuf->swbuf = align_malloc(template->width0, 64);
310 if(!sbuf->swbuf)
311 goto error2;
312 }
313
314 debug_reference(&sbuf->b.b.reference,
315 (debug_reference_descriptor)debug_describe_resource, 0);
316
317 return &sbuf->b.b;
318
319 error2:
320 FREE(sbuf);
321 error1:
322 return NULL;
323 }
324
325 struct pipe_resource *
326 svga_user_buffer_create(struct pipe_screen *screen,
327 void *ptr,
328 unsigned bytes,
329 unsigned bind)
330 {
331 struct svga_buffer *sbuf;
332
333 sbuf = CALLOC_STRUCT(svga_buffer);
334 if(!sbuf)
335 goto no_sbuf;
336
337 pipe_reference_init(&sbuf->b.b.reference, 1);
338 sbuf->b.vtbl = &svga_buffer_vtbl;
339 sbuf->b.b.screen = screen;
340 sbuf->b.b.format = PIPE_FORMAT_R8_UNORM; /* ?? */
341 sbuf->b.b.usage = PIPE_USAGE_IMMUTABLE;
342 sbuf->b.b.bind = bind;
343 sbuf->b.b.width0 = bytes;
344 sbuf->b.b.height0 = 1;
345 sbuf->b.b.depth0 = 1;
346 sbuf->b.b.array_size = 1;
347
348 sbuf->swbuf = ptr;
349 sbuf->user = TRUE;
350
351 debug_reference(&sbuf->b.b.reference,
352 (debug_reference_descriptor)debug_describe_resource, 0);
353
354 return &sbuf->b.b;
355
356 no_sbuf:
357 return NULL;
358 }
359
360
361